<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<HTML>
  <HEAD>
    <LINK href="default.css" rel="stylesheet" type="text/css">
  </HEAD>
  <BODY><PRE>
<span class="p_commentline"># Copyright (c) 2007, Kundan Singh. All rights reserved. See LICENSING for details.</span>

</PRE><DIV class="commentbox"><b>This file implements RFC3261 (SIP)</b></DIV><PRE>
</PRE><DIV class="commentbox"><b>This file implements RFC3581 (rport)</b></DIV><PRE>

<span class="p_triple">'''
The session initiation protocol (SIP) as per <a href="http://www.rfc-editor.org/rfc/rfc3261.txt">RFC 3261</a>.
In my code there is no performance optimization, if it hurts the style and
compactness of the code.
'''</span>

<span class="p_word">import</span> re, socket
<span class="p_word">from</span> kutil <span class="p_word">import</span> getlocaladdr
<span class="p_word">from</span> rfc2396 <span class="p_word">import</span> isIPv4, isMulticast, URI, Address
<span class="p_word">from</span> rfc2617 <span class="p_word">import</span> createAuthorization
<span class="p_word">from</span> socket <span class="p_word">import</span> gethostbyname <span class="p_commentline"># TODO: should replace with getifaddr, SRV, NAPTR or similar</span>

_debug = False

<span class="p_commentline">#----------------------- Header and Message -------------------------------</span>

_quote   = <span class="p_word">lambda</span> s: <span class="p_string">'"'</span> + s + <span class="p_string">'"'</span> <span class="p_word">if</span> s[<span class="p_number">0</span>] != <span class="p_string">'"'</span> != s[-<span class="p_number">1</span>] <span class="p_word">else</span> s
_unquote = <span class="p_word">lambda</span> s: s[<span class="p_number">1</span>:-<span class="p_number">1</span>] <span class="p_word">if</span> s[<span class="p_number">0</span>] == <span class="p_string">'"'</span> == s[-<span class="p_number">1</span>] <span class="p_word">else</span> s

<span class="p_commentline"># various header types: standard (default), address, comma and unstructured</span>
_address      = [<span class="p_string">'contact'</span>, <span class="p_string">'from'</span>, <span class="p_string">'record-route'</span>, <span class="p_string">'refer-to'</span>, <span class="p_string">'referred-by'</span>, <span class="p_string">'route'</span>, <span class="p_string">'to'</span>]
_comma        = [<span class="p_string">'authorization'</span>, <span class="p_string">'proxy-authenticate'</span>, <span class="p_string">'proxy-authorization'</span>, <span class="p_string">'www-authenticate'</span>]
_unstructured = [<span class="p_string">'call-id'</span>, <span class="p_string">'cseq'</span>, <span class="p_string">'date'</span>, <span class="p_string">'expires'</span>, <span class="p_string">'max-forwards'</span>, <span class="p_string">'organization'</span>, <span class="p_string">'server'</span>, <span class="p_string">'subject'</span>, <span class="p_string">'timestamp'</span>, <span class="p_string">'user-agent'</span>]
<span class="p_commentline"># short form of header names</span>
_short        = [<span class="p_string">'allow-events'</span>, <span class="p_string">'u'</span>, <span class="p_string">'call-id'</span>, <span class="p_string">'i'</span>, <span class="p_string">'contact'</span>, <span class="p_string">'m'</span>, <span class="p_string">'content-encoding'</span>, <span class="p_string">'e'</span>, <span class="p_string">'content-length'</span>, <span class="p_string">'l'</span>, <span class="p_string">'content-type'</span>, <span class="p_string">'c'</span>, <span class="p_string">'event'</span>, <span class="p_string">'o'</span>, <span class="p_string">'from'</span>, <span class="p_string">'f'</span>, <span class="p_string">'subject'</span>, <span class="p_string">'s'</span>, <span class="p_string">'supported'</span>, <span class="p_string">'k'</span>, <span class="p_string">'to'</span>, <span class="p_string">'t'</span>, <span class="p_string">'via'</span>, <span class="p_string">'v'</span>]
<span class="p_commentline"># exception for canonicalization of header names</span>
_exception    = {<span class="p_string">'call-id'</span>:<span class="p_string">'Call-ID'</span>,<span class="p_string">'cseq'</span>:<span class="p_string">'CSeq'</span>,<span class="p_string">'www-authenticate'</span>:<span class="p_string">'WWW-Authenticate'</span>}
<span class="p_commentline">#_canon   = lambda s: '-'.join([x.capitalize() for x in s.split('-')]) if s.lower() not in ['cseq','call-id','www-authenticate'] else {'cseq':'CSeq','call-id':'Call-ID','www-authenticate':'WWW-Authenticate'}[s.lower()]</span>

<span class="p_word">def</span> _canon(s):
    <span class="p_triple">'''Return the canonical form of the header.
    &gt;&gt;&gt; print _canon('call-Id'), _canon('fRoM'), _canon('refer-to')
    Call-ID From Refer-To
    '''</span>
    s = s.lower()
    <span class="p_word">return</span> ((len(s)==<span class="p_number">1</span>) <span class="p_word">and</span> s <span class="p_word">in</span> _short <span class="p_word">and</span> _canon(_short[_short.index(s)-<span class="p_number">1</span>])) \
        <span class="p_word">or</span> (s <span class="p_word">in</span> _exception <span class="p_word">and</span> _exception[s]) <span class="p_word">or</span> <span class="p_string">'-'</span>.join([x.capitalize() <span class="p_word">for</span> x <span class="p_word">in</span> s.split(<span class="p_string">'-'</span>)])
    

<span class="p_word">class</span> Header(object):
    <span class="p_triple">'''A SIP header object with dynamic properties.
    Attributes such as name, and various parameters can be accessed on the object.
    
    &gt;&gt;&gt; print repr(Header('"Kundan Singh" &lt;sip:kundan@example.net&gt;', 'To'))
    To: "Kundan Singh" &lt;sip:kundan@example.net&gt;
    &gt;&gt;&gt; print repr(Header('"Kundan"&lt;sip:kundan99@example.net&gt;', 'To'))
    To: "Kundan" &lt;sip:kundan99@example.net&gt;
    &gt;&gt;&gt; print repr(Header('Sanjay &lt;sip:sanjayc77@example.net&gt;', 'fRoM'))
    From: "Sanjay" &lt;sip:sanjayc77@example.net&gt;
    &gt;&gt;&gt; print repr(Header('application/sdp', 'conTenT-tyPe'))
    Content-Type: application/sdp
    &gt;&gt;&gt; print repr(Header('presence; param=value;param2=another', 'Event'))
    Event: presence;param=value;param2=another
    &gt;&gt;&gt; print repr(Header('78  INVITE', 'CSeq'))
    CSeq: 78 INVITE
    '''</span>
    
    <span class="p_word">def</span> __init__(self, value=<span class="p_word">None</span>, name=<span class="p_word">None</span>):
        <span class="p_triple">'''Construct a Header from optional value and optional name.'''</span>
        self.name = name <span class="p_word">and</span> _canon(name.strip()) <span class="p_word">or</span> <span class="p_word">None</span>
        self.value = self._parse(value.strip(), self.name <span class="p_word">and</span> self.name.lower() <span class="p_word">or</span> <span class="p_word">None</span>)
    
    <span class="p_word">def</span> _parse(self, value, name):
        <span class="p_triple">'''Parse a header string value for the given header name.'''</span> 
        <span class="p_word">if</span> name <span class="p_word">in</span> _address: <span class="p_commentline"># address header</span>
            addr = Address(); addr.mustQuote = True
            count = addr.parse(value)
            value, rest = addr, value[count:]
            <span class="p_word">if</span> rest:
                <span class="p_word">for</span> n,sep,v <span class="p_word">in</span> map(<span class="p_word">lambda</span> x: x.partition(<span class="p_string">'='</span>), rest.split(<span class="p_string">';'</span>) <span class="p_word">if</span> rest <span class="p_word">else</span> []):
                    <span class="p_word">if</span> n.strip():
                        self.__dict__[n.lower().strip()] = v.strip()
        <span class="p_word">elif</span> name <span class="p_word">not</span> <span class="p_word">in</span> _comma <span class="p_word">and</span> name <span class="p_word">not</span> <span class="p_word">in</span> _unstructured: <span class="p_commentline"># standard</span>
            value, sep, rest = value.partition(<span class="p_string">';'</span>)
            <span class="p_word">for</span> n,sep,v <span class="p_word">in</span> map(<span class="p_word">lambda</span> x: x.partition(<span class="p_string">'='</span>), rest.split(<span class="p_string">';'</span>) <span class="p_word">if</span> rest <span class="p_word">else</span> []):
                <span class="p_commentline"># TODO: add checks for token </span>
                self.__dict__[n.lower().strip()] = v.strip()
        <span class="p_word">if</span> name <span class="p_word">in</span> _comma:
            self.authMethod, sep, rest = value.strip().partition(<span class="p_string">' '</span>)
            <span class="p_word">for</span> n,v <span class="p_word">in</span> map(<span class="p_word">lambda</span> x: x.strip().split(<span class="p_string">'='</span>), rest.split(<span class="p_string">','</span>) <span class="p_word">if</span> rest <span class="p_word">else</span> []):
                self.__dict__[n.lower().strip()] = _unquote(v.strip())
        <span class="p_word">elif</span> name == <span class="p_string">'cseq'</span>:
            n, sep, self.method = map(<span class="p_word">lambda</span> x: x.strip(), value.partition(<span class="p_string">' '</span>))
            self.number = int(n); value = n + <span class="p_string">' '</span> + self.method
        <span class="p_word">return</span> value
    
    <span class="p_word">def</span> __str__(self):
        <span class="p_triple">'''Return a string representation of the header value.'''</span>
        <span class="p_commentline"># TODO: use reduce instead of join+map</span>
        name = self.name.lower()
        rest = <span class="p_string">''</span> <span class="p_word">if</span> ((name <span class="p_word">in</span> _comma) <span class="p_word">or</span> (name <span class="p_word">in</span> _unstructured)) \
                <span class="p_word">else</span> (<span class="p_string">';'</span>.join(map(<span class="p_word">lambda</span> x: self.__dict__[x] <span class="p_word">and</span> <span class="p_string">'%s=%s'</span>%(x.lower(),self.__dict__[x]) <span class="p_word">or</span> x, filter(<span class="p_word">lambda</span> x: x.lower() <span class="p_word">not</span> <span class="p_word">in</span> [<span class="p_string">'name'</span>,<span class="p_string">'value'</span>, <span class="p_string">'_viauri'</span>], self.__dict__))))
        <span class="p_word">return</span> str(self.value) + (rest <span class="p_word">and</span> (<span class="p_string">';'</span>+rest) <span class="p_word">or</span> <span class="p_string">''</span>);
    
    <span class="p_word">def</span> __repr__(self):
        <span class="p_triple">'''Return the string representation of header's "name: value"'''</span>
        <span class="p_word">return</span> self.name + <span class="p_string">": "</span> + str(self)
    
    <span class="p_word">def</span> dup(self):
        <span class="p_triple">'''Duplicate this object.'''</span>
        <span class="p_word">return</span> Header(self.__str__(), self.name)
    
    <span class="p_commentline"># container access for parameters: use lower-case key in __dict__</span>
    <span class="p_word">def</span> __getitem__(self, name): <span class="p_word">return</span> self.__dict__.get(name.lower(), <span class="p_word">None</span>)
    <span class="p_word">def</span> __setitem__(self, name, value): self.__dict__[name.lower()] = value
    <span class="p_word">def</span> __contains__(self, name): <span class="p_word">return</span> name.lower() <span class="p_word">in</span> self.__dict__
    
    @property
    <span class="p_word">def</span> viaUri(self):
        <span class="p_triple">'''Read-only URI representing Via header's value.
        &gt;&gt;&gt; print Header('SIP/2.0/UDP example.net:5090;ttl=1', 'Via').viaUri
        sip:example.net:5090;transport=udp
        &gt;&gt;&gt; print Header('SIP/2.0/UDP 192.1.2.3;rport=1078;received=76.17.12.18;branch=0', 'Via').viaUri
        sip:76.17.12.18:1078;transport=udp
        &gt;&gt;&gt; print Header('SIP/2.0/UDP 192.1.2.3;maddr=224.0.1.75', 'Via').viaUri
        sip:224.0.1.75:5060;transport=udp
        '''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> hasattr(self, <span class="p_string">'_viaUri'</span>):
            <span class="p_word">if</span> self.name != <span class="p_string">'Via'</span>: <span class="p_word">raise</span> ValueError, <span class="p_string">'viaUri available only on Via header'</span>
            proto, addr = self.value.split(<span class="p_string">' '</span>)
            type = proto.split(<span class="p_string">'/'</span>)[<span class="p_number">2</span>].lower()  <span class="p_commentline"># udp, tcp, tls</span>
            self._viaUri = URI(<span class="p_string">'sip:'</span> + addr + <span class="p_string">';transport='</span> + type)
            <span class="p_word">if</span> self._viaUri.port == <span class="p_word">None</span>: self._viaUri.port = <span class="p_number">5060</span>
            <span class="p_word">if</span> <span class="p_string">'rport'</span> <span class="p_word">in</span> self: 
                <span class="p_word">try</span>: self._viaUri.port = int(self.rport)
                <span class="p_word">except</span>: <span class="p_word">pass</span> <span class="p_commentline"># probably not an int</span>
            <span class="p_word">if</span> type <span class="p_word">not</span> <span class="p_word">in</span> [<span class="p_string">'tcp'</span>,<span class="p_string">'sctp'</span>,<span class="p_string">'tls'</span>]:
                <span class="p_word">if</span> <span class="p_string">'maddr'</span> <span class="p_word">in</span> self: self._viaUri.host = self.maddr
                <span class="p_word">elif</span> <span class="p_string">'received'</span> <span class="p_word">in</span> self: self._viaUri.host = self.received
        <span class="p_word">return</span> self._viaUri
    
    @staticmethod
    <span class="p_word">def</span> createHeaders(value):
        <span class="p_triple">'''Parse a header line and return (name, [Header, Header, Header]) where name
        represents the header name, and the list has list of Header objects, typically
        one but for comma separated header line there can be multiple.
        &gt;&gt;&gt; print Header.createHeaders('Event: presence, reg')
        ('Event', [Event: presence, Event: reg])
        '''</span>
        name, value = map(str.strip, value.split(<span class="p_string">':'</span>, <span class="p_number">1</span>))
        <span class="p_word">return</span> (_canon(name),  map(<span class="p_word">lambda</span> x: Header(x, name), value.split(<span class="p_string">','</span>) <span class="p_word">if</span> name.lower() <span class="p_word">not</span> <span class="p_word">in</span> _comma <span class="p_word">else</span> [value]))



<span class="p_word">class</span> Message(object):
    <span class="p_triple">'''A SIP message object with dynamic properties. 
    The header names can be accessed as attributes or items and 
    are case-insensitive. Attributes such as method, uri (URI),
    response (int), responsetext, protocol, and body are available.
    Accessing an unavailable header gives None instead of exception.
    
    &gt;&gt;&gt; m = Message()
    &gt;&gt;&gt; m.method = 'INVITE'
    '''</span>

    <span class="p_commentline"># non-header attributes or items</span>
    _keywords = [<span class="p_string">'method'</span>,<span class="p_string">'uri'</span>,<span class="p_string">'response'</span>,<span class="p_string">'responsetext'</span>,<span class="p_string">'protocol'</span>,<span class="p_string">'_body'</span>,<span class="p_string">'body'</span>]
    <span class="p_commentline"># headers that can appear only atmost once. subsequent occurance ignored.</span>
    _single = [<span class="p_string">'call-id'</span>, <span class="p_string">'content-disposition'</span>, <span class="p_string">'content-length'</span>, <span class="p_string">'content-type'</span>, <span class="p_string">'cseq'</span>, <span class="p_string">'date'</span>, <span class="p_string">'expires'</span>, <span class="p_string">'event'</span>, <span class="p_string">'max-forwards'</span>, <span class="p_string">'organization'</span>, <span class="p_string">'refer-to'</span>, <span class="p_string">'referred-by'</span>, <span class="p_string">'server'</span>, <span class="p_string">'session-expires'</span>, <span class="p_string">'subject'</span>, <span class="p_string">'timestamp'</span>, <span class="p_string">'to'</span>, <span class="p_string">'user-agent'</span>]
    
    <span class="p_word">def</span> __init__(self, value=<span class="p_word">None</span>):
        self.method = self.uri = self.response = self.responsetext = self.protocol = self._body = <span class="p_word">None</span>
        <span class="p_word">if</span> value: self._parse(value)
        
    <span class="p_commentline"># attribute access: use lower-case name, and use container if not found</span>
    <span class="p_word">def</span> __getattr__(self, name): <span class="p_word">return</span> self.__getitem__(name)
    <span class="p_word">def</span> __getattribute__(self, name): <span class="p_word">return</span> object.__getattribute__(self, name.lower())
    <span class="p_word">def</span> __setattr__(self, name, value): object.__setattr__(self, name.lower(), value)
    <span class="p_word">def</span> __delattr__(self, name): object.__delattr__(self, name.lower())
    <span class="p_word">def</span> __hasattr__(self, name): object.__hasattr__(self, name.lower())
    <span class="p_commentline"># container access: use lower-case key in __dict__</span>
    <span class="p_word">def</span> __getitem__(self, name): <span class="p_word">return</span> self.__dict__.get(name.lower(), <span class="p_word">None</span>)
    <span class="p_word">def</span> __setitem__(self, name, value): self.__dict__[name.lower()] = value
    <span class="p_word">def</span> __contains__(self, name): <span class="p_word">return</span> name.lower() <span class="p_word">in</span> self.__dict__
    
    <span class="p_word">def</span> _parse(self, value):
        <span class="p_triple">'''Parse a SIP message as this object. Throws exception on error'''</span>
        <span class="p_commentline"># TODO: perform all error checking:</span>
        <span class="p_commentline"># 1. no \r\n\r\n in the message.</span>
        <span class="p_commentline"># 2. no headers.</span>
        <span class="p_commentline"># 3. first line has less than three parts.</span>
        <span class="p_commentline"># 4. syntax for protocol, and must be SIP/2.0</span>
        <span class="p_commentline"># 5. syntax for method or response attributes</span>
        <span class="p_commentline"># 6. first header must not start with a space or tab.</span>
        <span class="p_commentline"># 7. detect and ignore header parsing and multiple instance errors.</span>
        <span class="p_commentline"># 8. Content-Length if present must match the length of body.</span>
        <span class="p_commentline"># 9. mandatory headers are To, From, Call-ID and CSeq.</span>
        <span class="p_commentline"># 10. syntax for top Via header and fields: ttl, maddr, received, branch.</span>
        firstheaders, body = value.split(<span class="p_string">'\r\n\r\n'</span>, <span class="p_number">1</span>)
        firstline, headers = firstheaders.split(<span class="p_string">'\r\n'</span>, <span class="p_number">1</span>)
        a, b, c = firstline.split(<span class="p_string">' '</span>, <span class="p_number">2</span>)
        <span class="p_word">try</span>:    <span class="p_commentline"># try as response</span>
            self.response, self.responsetext, self.protocol = int(b), c, a <span class="p_commentline"># throws error if b is not int.</span>
        <span class="p_word">except</span>: <span class="p_commentline"># probably a request</span>
            self.method, self.uri, self.protocol = a, URI(b), c
            
        <span class="p_word">for</span> h <span class="p_word">in</span> headers.split(<span class="p_string">'\r\n'</span>):
            <span class="p_word">if</span> h.startswith(<span class="p_string">r'[ \t]'</span>):
                <span class="p_word">pass</span>
            <span class="p_word">try</span>:
                name, values = Header.createHeaders(h)
                <span class="p_word">if</span> name <span class="p_word">not</span> <span class="p_word">in</span> self: <span class="p_commentline"># doesn't already exist</span>
                    self[name] = values <span class="p_word">if</span> len(values) &gt; <span class="p_number">1</span> <span class="p_word">else</span> values[<span class="p_number">0</span>]
                <span class="p_word">elif</span> name <span class="p_word">not</span> <span class="p_word">in</span> Message._single: <span class="p_commentline"># valid multiple-instance header</span>
                    <span class="p_word">if</span> <span class="p_word">not</span> isinstance(self[name],list): self[name] = [self[name]]
                    self[name] += values
            <span class="p_word">except</span>:
                <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'error parsing'</span>, h 
                <span class="p_word">continue</span>
        bodyLen = int(self[<span class="p_string">'Content-Length'</span>].value) <span class="p_word">if</span> <span class="p_string">'Content-Length'</span> <span class="p_word">in</span> self <span class="p_word">else</span> <span class="p_number">0</span>
        <span class="p_word">if</span> body: self.body = body
        <span class="p_word">if</span> self.body != <span class="p_word">None</span> <span class="p_word">and</span> bodyLen != len(body): <span class="p_word">raise</span> ValueError, <span class="p_string">'Invalid content-length %d!=%d'</span>%(bodyLen, len(body))
        <span class="p_word">for</span> h <span class="p_word">in</span> [<span class="p_string">'To'</span>,<span class="p_string">'From'</span>,<span class="p_string">'CSeq'</span>,<span class="p_string">'Call-ID'</span>]: 
            <span class="p_word">if</span> h <span class="p_word">not</span> <span class="p_word">in</span> self: <span class="p_word">raise</span> ValueError, <span class="p_string">'Mandatory header %s missing'</span>%(h)
        
    <span class="p_word">def</span> __repr__(self):
        <span class="p_triple">'''Return the formatted message string.'''</span>
        <span class="p_word">if</span> self.method != <span class="p_word">None</span>: m = self.method + <span class="p_string">' '</span> + str(self.uri) + <span class="p_string">' '</span> + self.protocol + <span class="p_string">'\r\n'</span>
        <span class="p_word">elif</span> self.response != <span class="p_word">None</span>: m = self.protocol + <span class="p_string">' '</span> + str(self.response) + <span class="p_string">' '</span> + self.responsetext + <span class="p_string">'\r\n'</span>
        <span class="p_word">else</span>: <span class="p_word">return</span> <span class="p_word">None</span> <span class="p_commentline"># invalid message</span>
        <span class="p_word">for</span> h <span class="p_word">in</span> self: 
            m += repr(h) + <span class="p_string">'\r\n'</span>
        m+= <span class="p_string">'\r\n'</span>
        <span class="p_word">if</span> self.body != <span class="p_word">None</span>: m += self.body
        <span class="p_word">return</span> m
    
    <span class="p_word">def</span> dup(self):
        <span class="p_triple">'''Duplicate this object.'''</span>
        <span class="p_word">return</span> Message(self.__repr__())
    
    <span class="p_word">def</span> __iter__(self):
        <span class="p_triple">'''Return iterator to iterate over all Header objects.'''</span>
        h = list()
        <span class="p_word">for</span> n <span class="p_word">in</span> filter(<span class="p_word">lambda</span> x: <span class="p_word">not</span> x.startswith(<span class="p_string">'_'</span>) <span class="p_word">and</span> x <span class="p_word">not</span> <span class="p_word">in</span> Message._keywords, self.__dict__):
            h += filter(<span class="p_word">lambda</span> x: isinstance(x, Header), self[n] <span class="p_word">if</span> isinstance(self[n],list) <span class="p_word">else</span> [self[n]])
        <span class="p_word">return</span> iter(h)
    
    <span class="p_word">def</span> first(self, name):
        <span class="p_triple">'''Return the first Header object for this name, or None.'''</span>
        result = self[name]
        <span class="p_word">return</span> isinstance(result,list) <span class="p_word">and</span> result[<span class="p_number">0</span>] <span class="p_word">or</span> result
    
    <span class="p_word">def</span> all(self, *args):
        <span class="p_triple">'''Return list of the Header object (or empty list) for all the header names in args.'''</span>
        args = map(<span class="p_word">lambda</span> x: x.lower(), args)
        h = list()
        <span class="p_word">for</span> n <span class="p_word">in</span> filter(<span class="p_word">lambda</span> x: x <span class="p_word">in</span> args <span class="p_word">and</span> <span class="p_word">not</span> x.startswith(<span class="p_string">'_'</span>) <span class="p_word">and</span> x <span class="p_word">not</span> <span class="p_word">in</span> Message._keywords, self.__dict__):
            h += filter(<span class="p_word">lambda</span> x: isinstance(x, Header), self[n] <span class="p_word">if</span> isinstance(self[n],list) <span class="p_word">else</span> [self[n]])
        <span class="p_word">return</span> h
        
    <span class="p_word">def</span> insert(self, header, append=False):
        <span class="p_word">if</span> header <span class="p_word">and</span> header.name:
            <span class="p_word">if</span> header.name <span class="p_word">not</span> <span class="p_word">in</span> self:
                self[header.name] = header
            <span class="p_word">elif</span> isinstance(self[header.name], Header):
                self[header.name] = (append <span class="p_word">and</span> [self[header.name], header] <span class="p_word">or</span> [header, self[header.name]])
            <span class="p_word">else</span>:
                <span class="p_word">if</span> append: self[header.name].append(header)
                <span class="p_word">else</span>: self[header.name].insert(<span class="p_number">0</span>, header)
        <span class="p_commentline"># TODO: don't insert multi-instance if single header type.</span>
    
    <span class="p_word">def</span> delete(self, name, position=<span class="p_word">None</span>): 
        <span class="p_triple">'''Delete a named header, either all (default) or at given position (0 for first, -1 for last).'''</span>
        <span class="p_word">if</span> position <span class="p_word">is</span> <span class="p_word">None</span>: <span class="p_word">del</span> self[name] <span class="p_commentline"># remove all headers with this name</span>
        <span class="p_word">else</span>:
            h = self.all(name) <span class="p_commentline"># get all headers</span>
            <span class="p_word">try</span>: <span class="p_word">del</span> h[position]    <span class="p_commentline"># and remove at given position</span>
            <span class="p_word">except</span>: <span class="p_word">pass</span>       <span class="p_commentline"># ignore any error in index</span>
            <span class="p_word">if</span> len(h) == <span class="p_number">0</span>: <span class="p_word">del</span> self[name]
            <span class="p_word">else</span>: self[name] = h[<span class="p_number">0</span>] <span class="p_word">if</span> len(h) == <span class="p_number">1</span> <span class="p_word">else</span> h
            
    <span class="p_word">def</span> body():
        <span class="p_triple">'''The body property, when set also sets the Content-Length header field.'''</span>
        <span class="p_word">def</span> fset(self, value):
            self._body = value
            self[<span class="p_string">'Content-Length'</span>] = Header(<span class="p_string">'%d'</span>%(value <span class="p_word">and</span> len(value) <span class="p_word">or</span> <span class="p_number">0</span>), <span class="p_string">'Content-Length'</span>)
        <span class="p_word">def</span> fget(self):
            <span class="p_word">return</span> self._body
        <span class="p_word">return</span> locals()
    body = property(**body())
        
    @staticmethod
    <span class="p_word">def</span> _populateMessage(m, headers=<span class="p_word">None</span>, content=<span class="p_word">None</span>):
        <span class="p_triple">'''Modify m to add headers (list of Header objects) and content (str body)'''</span>
        <span class="p_word">if</span> headers: 
            <span class="p_word">for</span> h <span class="p_word">in</span> headers: m.insert(h, True) <span class="p_commentline"># append the header instead of overriding</span>
        <span class="p_word">if</span> content: m.body = content
        <span class="p_word">else</span>: m[<span class="p_string">'Content-Length'</span>] = Header(<span class="p_string">'0'</span>, <span class="p_string">'Content-Length'</span>)
        
    @staticmethod
    <span class="p_word">def</span> createRequest(method, uri, headers=<span class="p_word">None</span>, content=<span class="p_word">None</span>):
        <span class="p_triple">'''Create a new request Message with given attributes.'''</span>
        m = Message()
        m.method, m.uri, m.protocol = method, URI(uri), <span class="p_string">'SIP/2.0'</span>
        Message._populateMessage(m, headers, content)
        <span class="p_word">if</span> m.CSeq != <span class="p_word">None</span> <span class="p_word">and</span> m.CSeq.method != method: m.CSeq = Header(str(m.CSeq.number) + <span class="p_string">' '</span> + method, <span class="p_string">'CSeq'</span>)
        <span class="p_commentline">#if _debug: print 'createRequest returned\n', m </span>
        <span class="p_word">return</span> m
    
    @staticmethod
    <span class="p_word">def</span> createResponse(response, responsetext, headers=<span class="p_word">None</span>, content=<span class="p_word">None</span>, r=<span class="p_word">None</span>):
        <span class="p_triple">'''Create a new response Message with given attributes.
        The original request may be specified as the r parameter.'''</span>
        m = Message()
        m.response, m.responsetext, m.protocol = response, responsetext, <span class="p_string">'SIP/2.0'</span>
        <span class="p_word">if</span> r: 
            m.To, m.From, m.CSeq, m[<span class="p_string">'Call-ID'</span>], m.Via = r.To, r.From, r.CSeq, r[<span class="p_string">'Call-ID'</span>], r.Via
            <span class="p_word">if</span> response == <span class="p_number">100</span>: m.Timestamp = r.Timestamp
        Message._populateMessage(m, headers, content)
        <span class="p_word">return</span> m

    <span class="p_commentline"># define is1xx, is2xx, ... is6xx and isfinal</span>
    <span class="p_word">for</span> x <span class="p_word">in</span> range(<span class="p_number">1</span>,<span class="p_number">7</span>):
        <span class="p_word">exec</span> <span class="p_string">'def is%dxx(self): return self.response and (self.response / 100 == %d)'</span>%(x,x)
        <span class="p_word">exec</span> <span class="p_string">'is%dxx = property(is%dxx)'</span>%(x,x)
    @property
    <span class="p_word">def</span> isfinal(self): <span class="p_word">return</span> self.response <span class="p_word">and</span> (self.response &gt;= <span class="p_number">200</span>)

<span class="p_commentline">#---------------------------Stack------------------------------------------</span>

<span class="p_word">import</span> random

<span class="p_word">class</span> Stack(object):
    <span class="p_triple">'''The SIP stack is associated with transport layer and controls message
    flow among different layers. 
    
    The application must provide an app instance with following signature:
    class App():
        def send(self, data, dest): pass
            'to send data (str) to dest ('192.1.2.3', 5060).'
        def sending(self, data, dest): pass
            'to indicate that a given data (Message) will be sent to the dest (host, port).'
        def createServer(self, request, uri): return UserAgent(stack, request)
            'to ask the application to create a UAS for this request (Message) from source uri (Uri).'
        def receivedRequest(self, ua, request): pass
            'to inform that the UAS or Dialog has recived a new request (Message).'
        def receivedResponse(self, ua, request): pass
            'to inform that the UAC or Dialog has recived a new response (Message).'
        def cancelled(self, ua, request): pass
            'to inform that the UAS or Dialog has received a cancel for original request (Message).'
        def dialogCreated(self, dialog, ua): pass
            'to inform that the a new Dialog is created from the old UserAgent.'
        def authenticate(self, ua, header): header.password='mypass'; return True
            'to ask the application for credentials for this challenge header (Header).'
        def createTimer(self, cbObj): return timerObject
            'the returned timer object must have start() and stop() methods, a delay (int)
            attribute, and should invoke cbObj.timedout(timer) when the timer expires.'
    
    The application must invoke the following callback on the stack:
    stack.received(data, src) 
        'when incoming data (str) received on underlying transport from 
        src ('192.2.2.2', 5060).'
    
    The application must provide a Transport object which is an object with 
    these attributes: host, port, type, secure, reliable, congestionControlled, where
        host: a string representing listening IP address, e.g., '192.1.2.3'
        port: a int representing listening port number, e.g., 5060.
        type: a string of the form 'udp', 'tcp', 'tls', or 'sctp' indicating the transport type.
        secure: a boolean indicating whether this is secure or not?
        reliable: a boolean indicating whether the transport is reliable or not?
        congestionControlled: a boolean indicating whether the transport is congestion controlled?
    '''</span>
    <span class="p_word">def</span> __init__(self, app, transport):
        <span class="p_triple">'''Construct a stack using the specified application (higher) layer and
        transport (lower) data.'''</span>
        self.tag = str(random.randint(<span class="p_number">0</span>,<span class="p_number">2</span>**<span class="p_number">31</span>))
        self.app, self.transport = app, transport
        self.closing = False
        self.dialogs, self.transactions = dict(), dict()
        self.serverMethods = [<span class="p_string">'INVITE'</span>,<span class="p_string">'BYE'</span>,<span class="p_string">'MESSAGE'</span>,<span class="p_string">'SUBSCRIBE'</span>,<span class="p_string">'NOTIFY'</span>]
    <span class="p_word">def</span> __del__(self):
        self.closing = True
        <span class="p_word">for</span> d <span class="p_word">in</span> self.dialogs: <span class="p_word">del</span> self.dialogs[d]
        <span class="p_word">for</span> t <span class="p_word">in</span> self.transactions: <span class="p_word">del</span> self.transactions[t]
        <span class="p_word">del</span> self.dialogs; <span class="p_word">del</span> self.transactions

    @property
    <span class="p_word">def</span> uri(self): 
        <span class="p_triple">'''Construct a URI for the transport.'''</span>
        transport = self.transport
        <span class="p_word">return</span> URI(((transport.type == <span class="p_string">'tls'</span>) <span class="p_word">and</span> <span class="p_string">'sips'</span> <span class="p_word">or</span> <span class="p_string">'sip'</span>) + <span class="p_string">':'</span> + transport.host + <span class="p_string">':'</span> + str(transport.port))
    
    @property
    <span class="p_word">def</span> newCallId(self): 
        <span class="p_word">return</span> str(random.randint(<span class="p_number">0</span>,<span class="p_number">2</span>**<span class="p_number">31</span>)) + <span class="p_string">'@'</span> + (self.transport.host <span class="p_word">or</span> <span class="p_string">'localhost'</span>)
    
    <span class="p_word">def</span> createVia(self, secure=False):
        <span class="p_word">if</span> <span class="p_word">not</span> self.transport: <span class="p_word">raise</span> ValueError, <span class="p_string">'No transport in stack'</span>
        <span class="p_word">if</span> secure <span class="p_word">and</span> <span class="p_word">not</span> self.transport.secure: <span class="p_word">raise</span> ValueError, <span class="p_string">'Cannot find a secure transport'</span>
        <span class="p_word">return</span> Header(<span class="p_string">'SIP/2.0/'</span> + self.transport.type.upper() + <span class="p_string">' '</span> + self.transport.host + <span class="p_string">':'</span> + str(self.transport.port) + <span class="p_string">';rport'</span>, <span class="p_string">'Via'</span>)

    <span class="p_word">def</span> send(self, data, dest=<span class="p_word">None</span>, transport=<span class="p_word">None</span>):
        <span class="p_triple">'''Send a data (Message) to given dest (URI or hostPort), or using the Via header of 
        response message if dest is missing.'''</span>
        <span class="p_word">if</span> dest <span class="p_word">and</span> isinstance(dest, URI):
            <span class="p_word">if</span> <span class="p_word">not</span> uri.host: <span class="p_word">raise</span> ValueError, <span class="p_string">'No host in destination uri'</span>
            dest = (dest.host, dest.port <span class="p_word">or</span> self.transport.type == <span class="p_string">'tls'</span> <span class="p_word">and</span> self.transport.secure <span class="p_word">and</span> <span class="p_number">5061</span> <span class="p_word">or</span> <span class="p_number">5060</span>)
        <span class="p_word">if</span> isinstance(data, Message):
            <span class="p_word">if</span> data.method:      <span class="p_commentline"># request</span>

</PRE><DIV class="commentbox">From RFC3261 p.143<pre>   A client that sends a request to a multicast address MUST add the
   "maddr" parameter to its Via header field value containing the
   destination multicast address, and for IPv4, SHOULD add the "ttl"
   parameter with a value of 1.  Usage of IPv6 multicast is not defined
   in this specification, and will be a subject of future
   standardization when the need arises.</pre></DIV><PRE>
                <span class="p_word">if</span> dest <span class="p_word">and</span> isMulticast(dest[<span class="p_number">0</span>]):
                    data.first(<span class="p_string">'Via'</span>)[<span class="p_string">'maddr'</span>], data.first(<span class="p_string">'Via'</span>)[<span class="p_string">'ttl'</span>] = dest[<span class="p_number">0</span>], <span class="p_number">1</span> 
            <span class="p_word">elif</span> data.response: <span class="p_commentline"># response: use Via if dest missing</span>
                <span class="p_word">if</span> <span class="p_word">not</span> dest: 
                    dest = data.first(<span class="p_string">'Via'</span>).viaUri.hostPort
        self.app.send(str(data), dest, stack=self)
        
    <span class="p_word">def</span> received(self, data, src):
        <span class="p_triple">'''Callback when received some data (str) from the src ('host', port).'''</span>
        <span class="p_word">try</span>:
            m = Message(data)
            uri = URI((self.transport.secure <span class="p_word">and</span> <span class="p_string">'sips'</span> <span class="p_word">or</span> <span class="p_string">'sip'</span>) + <span class="p_string">':'</span> + str(src[<span class="p_number">0</span>]) + <span class="p_string">':'</span> + str(src[<span class="p_number">1</span>]))
            <span class="p_word">if</span> m.method: <span class="p_commentline"># request: update Via and call receivedRequest</span>
                <span class="p_word">if</span> m.Via == <span class="p_word">None</span>: <span class="p_word">raise</span> ValueError, <span class="p_string">'No Via header in request'</span>
                via = m.first(<span class="p_string">'Via'</span>)
                <span class="p_word">if</span> via.viaUri.host != src[<span class="p_number">0</span>] <span class="p_word">or</span> via.viaUri.port != src[<span class="p_number">1</span>]: 
                    via[<span class="p_string">'received'</span>], via.viaUri.host = src[<span class="p_number">0</span>], src[<span class="p_number">0</span>]
                <span class="p_word">if</span> <span class="p_string">'rport'</span> <span class="p_word">in</span> via: via[<span class="p_string">'rport'</span>] = src[<span class="p_number">1</span>]
                via.viaUri.port = src[<span class="p_number">1</span>]
                self._receivedRequest(m, uri)
            <span class="p_word">elif</span> m.response: <span class="p_commentline"># response: call receivedResponse</span>
                self._receivedResponse(m, uri)
            <span class="p_word">else</span>: <span class="p_word">raise</span> ValueError, <span class="p_string">'Received invalid message'</span>
        <span class="p_word">except</span> ValueError, E: <span class="p_commentline"># TODO: send 400 response to non-ACK request</span>
            <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'Error in received message:'</span>, E
            
    <span class="p_word">def</span> _receivedRequest(self, r, uri):
        <span class="p_triple">'''Received a SIP request r (Message) from the uri (URI).'''</span>
        branch = r.first(<span class="p_string">'Via'</span>).branch
        <span class="p_word">if</span> r.method == <span class="p_string">'ACK'</span> <span class="p_word">and</span> branch == <span class="p_string">'0'</span>: 
            <span class="p_commentline"># TODO: this is a hack to work around iptel.org which puts branch=0 in all ACK</span>
            <span class="p_commentline"># hence it matches the previous transaction's ACK for us, which is not good. </span>
            <span class="p_commentline"># We need to fix our code to handle end-to-end ACK correctly in findTransaction.</span>
            t = <span class="p_word">None</span>
        <span class="p_word">else</span>:
            t = self.findTransaction(Transaction.createId(branch, r.method))
        <span class="p_word">if</span> <span class="p_word">not</span> t: <span class="p_commentline"># no transaction found</span>
            app = <span class="p_word">None</span>  <span class="p_commentline"># the application layer for further processing</span>
            <span class="p_word">if</span> r.method != <span class="p_string">'CANCEL'</span> <span class="p_word">and</span> <span class="p_string">'tag'</span> <span class="p_word">in</span> r.To: <span class="p_commentline"># for existing dialog</span>
                d = self.findDialog(r)
                <span class="p_word">if</span> <span class="p_word">not</span> d: <span class="p_commentline"># no dialog found</span>
                    <span class="p_word">if</span> r.method != <span class="p_string">'ACK'</span>:
                        u = self.createServer(r, uri)
                        <span class="p_word">if</span> u: app = u
                        <span class="p_word">else</span>:
                            self.send(Message.createResponse(<span class="p_number">481</span>, <span class="p_string">'Dialog does not exist'</span>, <span class="p_word">None</span>, <span class="p_word">None</span>, r))
                            <span class="p_word">return</span>
                    <span class="p_word">else</span>: <span class="p_commentline"># hack to locate original t for ACK</span>
                        <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'no dialog for ACK, finding transaction'</span>
                        <span class="p_word">if</span> <span class="p_word">not</span> t <span class="p_word">and</span> branch != <span class="p_string">'0'</span>: t = self.findTransaction(Transaction.createId(branch, <span class="p_string">'INVITE'</span>))
                        <span class="p_word">if</span> t:
                             t.receivedRequest(r)
                             <span class="p_word">return</span>
                        <span class="p_word">else</span>: 
                            <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'No existing transaction for ACK'</span>
                            u = self.createServer(r, uri)
                            <span class="p_word">if</span> u: app = u
                            <span class="p_word">else</span>: 
                                <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'Ignoring ACK without transaction'</span>
                                <span class="p_word">return</span>
                <span class="p_word">else</span>: <span class="p_commentline"># dialog found</span>
                    app = d
            <span class="p_word">elif</span> r.method != <span class="p_string">'CANCEL'</span>: <span class="p_commentline"># process all other out-of-dialog request except CANCEL</span>
                u = self.createServer(r, uri)
                <span class="p_word">if</span> u: 
                    app = u
                <span class="p_word">elif</span> r.method == <span class="p_string">'OPTIONS'</span>:
                    m = Message.createResponse(<span class="p_number">200</span>, <span class="p_string">'OK'</span>, <span class="p_word">None</span>, <span class="p_word">None</span>, r)
                    m.Allow = Header(<span class="p_string">'INVITE, ACK, CANCEL, BYE, OPTIONS'</span>, <span class="p_string">'Allow'</span>)
                    self.send(m)
                    <span class="p_word">return</span>
                <span class="p_word">elif</span> r.method != <span class="p_string">'ACK'</span>: 
                    self.send(Message.createResponse(<span class="p_number">405</span>, <span class="p_string">'Method not allowed'</span>, <span class="p_word">None</span>, <span class="p_word">None</span>, r))
                    <span class="p_word">return</span>
            <span class="p_word">else</span>: <span class="p_commentline"># Process a CANCEL request</span>
                o = self.findTransaction(Transaction.createId(r.first(<span class="p_string">'Via'</span>).branch, <span class="p_string">'INVITE'</span>)) <span class="p_commentline"># original transaction</span>
                <span class="p_word">if</span> <span class="p_word">not</span> o: 
                    self.send(Message.createResponse(<span class="p_number">481</span>, <span class="p_string">"Original transaction does not exist"</span>, <span class="p_word">None</span>, <span class="p_word">None</span>, r))
                    <span class="p_word">return</span>
                <span class="p_word">else</span>:
                    app = o.app
            <span class="p_word">if</span> app:
                t = app.createTransaction(r) 
                <span class="p_commentline">#t = Transaction.createServer(self, app, r, self.transport, self.tag)</span>
            <span class="p_word">elif</span> r.method != <span class="p_string">'ACK'</span>:
                self.send(Message.createResponse(<span class="p_number">404</span>, <span class="p_string">"Not found"</span>, <span class="p_word">None</span>, <span class="p_word">None</span>, r))
        <span class="p_word">else</span>:
            t.receivedRequest(r)
        
    <span class="p_word">def</span> _receivedResponse(self, r, uri):
        <span class="p_triple">'''Received a SIP response r (Message) from the uri (URI).'''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> r.Via: <span class="p_word">raise</span> ValueError, <span class="p_string">'No Via header in received response'</span>
        branch = r.first(<span class="p_string">'Via'</span>).branch
        method = r.CSeq.method
        t = self.findTransaction(Transaction.createId(branch, method))
        <span class="p_word">if</span> <span class="p_word">not</span> t:
            <span class="p_word">if</span> method == <span class="p_string">'INVITE'</span> <span class="p_word">and</span> r.is2xx: <span class="p_commentline"># success of INVITE</span>
                d = self.findDialog(r)
                <span class="p_word">if</span> <span class="p_word">not</span> d: <span class="p_word">raise</span> ValueError, <span class="p_string">'No transaction or dialog for 2xx of INVITE'</span>
                <span class="p_word">else</span>: d.receivedResponse(<span class="p_word">None</span>, r)
            <span class="p_word">else</span>: <span class="p_word">raise</span> ValueError, <span class="p_string">'No transaction for response'</span>
        <span class="p_word">else</span>:
            t.receivedResponse(r)
        
    <span class="p_commentline"># following are the main API methods to indicate events from UAS/UAC/Dialog</span>
    <span class="p_word">def</span> createServer(self, request, uri): <span class="p_word">return</span> self.app.createServer(request, uri, self)
    <span class="p_word">def</span> sending(self, ua, message): self.app.sending(ua, message, self)
    <span class="p_word">def</span> receivedRequest(self, ua, request): self.app.receivedRequest(ua, request, self)
    <span class="p_word">def</span> receivedResponse(self, ua, response): self.app.receivedResponse(ua, response, self)
    <span class="p_word">def</span> cancelled(self, ua, request): self.app.cancelled(ua, request, self)
    <span class="p_word">def</span> dialogCreated(self, dialog, ua): self.app.dialogCreated(dialog, ua, self)
    <span class="p_word">def</span> authenticate(self, ua, header): <span class="p_word">return</span> self.app.authenticate(ua, header, self)
    <span class="p_word">def</span> createTimer(self, obj): <span class="p_word">return</span> self.app.createTimer(obj, self)
    
    <span class="p_word">def</span> findDialog(self, arg):
        <span class="p_triple">'''Find an existing dialog for given id (str) or received message (Message).'''</span>
        <span class="p_word">return</span> self.dialogs.get(isinstance(arg, Message) <span class="p_word">and</span> Dialog.extractId(arg) <span class="p_word">or</span> str(arg), <span class="p_word">None</span>)
    
    <span class="p_word">def</span> findTransaction(self, id):
        <span class="p_triple">'''Find an existing transaction for given id (str).'''</span>
        <span class="p_word">return</span> self.transactions.get(id, <span class="p_word">None</span>)
    
    <span class="p_word">def</span> findOtherTransaction(self, r, orig):
        <span class="p_triple">'''Find another transaction other than orig (Transaction) for this request r (Message).'''</span>
        <span class="p_word">for</span> t <span class="p_word">in</span> self.transactions.values():
            <span class="p_word">if</span> t != orig <span class="p_word">and</span> Transaction.equals(t, r, orig): <span class="p_word">return</span> t
        <span class="p_word">return</span> <span class="p_word">None</span>

<span class="p_word">class</span> TransportInfo:  
    <span class="p_triple">'''Transport information needed by Stack constructor'''</span>
    <span class="p_word">def</span> __init__(self, sock, secure=False):
        <span class="p_triple">'''The sock argument is the bound socket.'''</span>
        addr = getlocaladdr(sock)
        self.host, self.port, self.type, self.secure, self.reliable, self.congestionControlled = addr[<span class="p_number">0</span>], addr[<span class="p_number">1</span>], (sock.type==socket.SOCK_DGRAM <span class="p_word">and</span> <span class="p_string">'udp'</span> <span class="p_word">or</span> <span class="p_string">'tcp'</span>), secure, (sock.type==socket.SOCK_STREAM), (sock.type==socket.SOCK_STREAM) 
<span class="p_commentline">#---------------------------Transaction------------------------------------</span>

<span class="p_word">from</span> hashlib <span class="p_word">import</span> md5
<span class="p_word">from</span> base64 <span class="p_word">import</span> urlsafe_b64encode


</PRE><DIV class="commentbox">From RFC3261 p.122<pre>17 Transactions

   SIP is a transactional protocol: interactions between components take
   place in a series of independent message exchanges.  Specifically, a
   SIP transaction consists of a single request and any responses to
   that request, which include zero or more provisional responses and
   one or more final responses.  In the case of a transaction where the
   request was an INVITE (known as an INVITE transaction), the
   transaction also includes the ACK only if the final response was not
   a 2xx response.  If the response was a 2xx, the ACK is not considered
   part of the transaction.

      The reason for this separation is rooted in the importance of
      delivering all 200 (OK) responses to an INVITE to the UAC.  To
      deliver them all to the UAC, the UAS alone takes responsibility
      for retransmitting them (see Section 13.3.1.4), and the UAC alone
      takes responsibility for acknowledging them with ACK (see Section
      13.2.2.4).  Since this ACK is retransmitted only by the UAC, it is
      effectively considered its own transaction.

   Transactions have a client side and a server side.  The client side
   is known as a client transaction and the server side as a server
   transaction.  The client transaction sends the request, and the
   server transaction sends the response.  The client and server
   transactions are logical functions that are embedded in any number of
   elements.  Specifically, they exist within user agents and stateful
   proxy servers.  Consider the example in Section 4.  In this example,
   the UAC executes the client transaction, and its outbound proxy
   executes the server transaction.  The outbound proxy also executes a
   client transaction, which sends the request to a server transaction
   in the inbound proxy.  That proxy also executes a client transaction,
   which in turn sends the request to a server transaction in the UAS.
   This is shown in Figure 4.

   +---------+        +---------+        +---------+        +---------+
   |      +-+|Request |+-+   +-+|Request |+-+   +-+|Request |+-+      |
   |      |C||-------&amp;gt;||S|   |C||-------&amp;gt;||S|   |C||-------&amp;gt;||S|      |
   |      |l||        ||e|   |l||        ||e|   |l||        ||e|      |
   |      |i||        ||r|   |i||        ||r|   |i||        ||r|      |
   |      |e||        ||v|   |e||        ||v|   |e||        ||v|      |
   |      |n||        ||e|   |n||        ||e|   |n||        ||e|      |
   |      |t||        ||r|   |t||        ||r|   |t||        ||r|      |
   |      | ||        || |   | ||        || |   | ||        || |      |
   |      |T||        ||T|   |T||        ||T|   |T||        ||T|      |
   |      |r||        ||r|   |r||        ||r|   |r||        ||r|      |
   |      |a||        ||a|   |a||        ||a|   |a||        ||a|      |
   |      |n||        ||n|   |n||        ||n|   |n||        ||n|      |
   |      |s||Response||s|   |s||Response||s|   |s||Response||s|      |
   |      +-+|&amp;lt;-------|+-+   +-+|&amp;lt;-------|+-+   +-+|&amp;lt;-------|+-+      |
   +---------+        +---------+        +---------+        +---------+
      UAC               Outbound           Inbound              UAS
                        Proxy               Proxy

                  Figure 4: Transaction relationships

   A stateless proxy does not contain a client or server transaction.
   The transaction exists between the UA or stateful proxy on one side,
   and the UA or stateful proxy on the other side.  As far as SIP
   transactions are concerned, stateless proxies are effectively
   transparent.  The purpose of the client transaction is to receive a
   request from the element in which the client is embedded (call this
   element the "Transaction User" or TU; it can be a UA or a stateful
   proxy), and reliably deliver the request to a server transaction.
   The client transaction is also responsible for receiving responses
   and delivering them to the TU, filtering out any response
   retransmissions or disallowed responses (such as a response to ACK).
   Additionally, in the case of an INVITE request, the client
   transaction is responsible for generating the ACK request for any
   final response accepting a 2xx response.

   Similarly, the purpose of the server transaction is to receive
   requests from the transport layer and deliver them to the TU.  The
   server transaction filters any request retransmissions from the
   network.  The server transaction accepts responses from the TU and
   delivers them to the transport layer for transmission over the
   network.  In the case of an INVITE transaction, it absorbs the ACK
   request for any final response excepting a 2xx response.

   The 2xx response and its ACK receive special treatment.  This
   response is retransmitted only by a UAS, and its ACK generated only
   by the UAC.  This end-to-end treatment is needed so that a caller
   knows the entire set of users that have accepted the call.  Because
   of this special handling, retransmissions of the 2xx response are
   handled by the UA core, not the transaction layer.  Similarly,
   generation of the ACK for the 2xx is handled by the UA core.  Each
   proxy along the path merely forwards each 2xx response to INVITE and
   its corresponding ACK.</pre></DIV><PRE>
<span class="p_word">class</span> Transaction(object):
    <span class="p_word">def</span> __init__(self, server):
        <span class="p_triple">'''Construct a transaction for the SIP method (str) and server (True or False)
        parameters, and uses the Invite/Non-invite Server/Client state machine accordingly.'''</span>
        self.branch = self.id = self.stack = self.app = self.request = self.transport = self.remote = self.tag = <span class="p_word">None</span>
        self.server, self.timers, self.timer = server, {}, Timer()
        
    <span class="p_word">def</span> close(self):
        <span class="p_triple">'''Stop the timers and remove from the lists.'''</span>
        self.stopTimers()
        <span class="p_word">if</span> self.stack:
            <span class="p_word">if</span> self.id <span class="p_word">in</span> self.stack.transactions: <span class="p_word">del</span> self.stack.transactions[self.id]

    <span class="p_word">def</span> state():
        <span class="p_word">def</span> fset(self, value): 
            self._state = value
            <span class="p_word">if</span> self._state == <span class="p_string">'terminating'</span>: self.close() <span class="p_commentline"># automatically close when state goes terminating</span>
        <span class="p_word">def</span> fget(self): <span class="p_word">return</span> self._state
        <span class="p_word">return</span> locals()
    state = property(**state())
    
    @property
    <span class="p_word">def</span> headers(self):
        <span class="p_triple">'''Read-only list of transaction Header objects (To, From, CSeq, Call-ID)'''</span>
        <span class="p_word">return</span> map(<span class="p_word">lambda</span> x: self.request[x], [<span class="p_string">'To'</span>, <span class="p_string">'From'</span>, <span class="p_string">'CSeq'</span>, <span class="p_string">'Call-ID'</span>])
    
    @staticmethod
    <span class="p_word">def</span> createBranch(request, server):
        <span class="p_triple">'''Static method to create a branch parameter from request (Message) and server (Boolean)
        or using [To, From, Call-ID, CSeq-number(int)] and server (Boolean).'''</span>
        To, From, CallId, CSeq = (request.To.value, request.From.value, request[<span class="p_string">'Call-ID'</span>].value, request.CSeq.number) <span class="p_word">if</span> isinstance(request, Message) <span class="p_word">else</span> (request[<span class="p_number">0</span>], request[<span class="p_number">1</span>], request[<span class="p_number">2</span>], request[<span class="p_number">3</span>])
        data = str(To).lower() + <span class="p_string">'|'</span> + str(From).lower() + <span class="p_string">'|'</span> + str(CallId) + <span class="p_string">'|'</span> + str(CSeq) + <span class="p_string">'|'</span> + str(server)
        <span class="p_word">return</span> <span class="p_string">'z9hG4bK'</span> + str(urlsafe_b64encode(md5(data).digest())).replace(<span class="p_string">'='</span>,<span class="p_string">'.'</span>)

    @staticmethod
    <span class="p_word">def</span> createId(branch, method):
        <span class="p_triple">'''Static method to create a transaction identifier form branch and method'''</span>
        <span class="p_word">return</span> branch <span class="p_word">if</span> method != <span class="p_string">'ACK'</span> <span class="p_word">and</span> method != <span class="p_string">'CANCEL'</span> <span class="p_word">else</span> branch + <span class="p_string">'|'</span> + method
    
    @staticmethod
    <span class="p_word">def</span> createServer(stack, app, request, transport, tag, start=True):
        <span class="p_triple">'''Static method to create a server transaction.'''</span>
        t = request.method == <span class="p_string">'INVITE'</span> <span class="p_word">and</span> InviteServerTransaction() <span class="p_word">or</span> ServerTransaction()
        t.stack, t.app, t.request, t.transport, t.tag = stack, app, request, transport, tag
        t.remote = request.first(<span class="p_string">'Via'</span>).viaUri.hostPort
        t.branch = request.first(<span class="p_string">'Via'</span>).branch <span class="p_word">if</span> request.Via != <span class="p_word">None</span> <span class="p_word">and</span> <span class="p_string">'branch'</span> <span class="p_word">in</span> request.first(<span class="p_string">'Via'</span>) <span class="p_word">else</span> Transaction.createBranch(request, True) 
        t.id = Transaction.createId(t.branch, request.method)
        stack.transactions[t.id] = t
        <span class="p_word">if</span> start: t.start() <span class="p_commentline"># invoke callback in UAS</span>
        <span class="p_word">else</span>: t.state = <span class="p_string">'trying'</span> <span class="p_commentline"># already invoked callback in UAS</span>
        <span class="p_word">return</span> t
    
    @staticmethod
    <span class="p_word">def</span> createClient(stack, app, request, transport, remote):
        <span class="p_triple">'''Static method to create a client transaction.'''</span>
        t = request.method == <span class="p_string">'INVITE'</span> <span class="p_word">and</span> InviteClientTransaction() <span class="p_word">or</span> ClientTransaction()
        t.stack, t.app, t.request, t.remote, t.transport = stack, app, request, remote, transport
        t.branch = request.first(<span class="p_string">'Via'</span>).branch <span class="p_word">if</span> request.Via != <span class="p_word">None</span> <span class="p_word">and</span> <span class="p_string">'branch'</span> <span class="p_word">in</span> request.first(<span class="p_string">'Via'</span>) <span class="p_word">else</span> Transaction.createBranch(request, False) 
        t.id = Transaction.createId(t.branch, request.method)
        stack.transactions[t.id] = t
        t.start()
        <span class="p_word">return</span> t
    
    @staticmethod
    <span class="p_word">def</span> equals(t1, r, t2):
        <span class="p_triple">'''Compare transaction t1 with new request r and original transaction t2.'''</span>
        t = t1.request
        <span class="p_commentline">#return  r.To.value.uri == t.To.value.uri and r.From.value.uri == t.From.value.uri \</span>
        <span class="p_commentline">#    and r['Call-ID'].value == t['Call-ID'].value and r.CSeq.value == t.CSeq.value \</span>
        <span class="p_commentline">#    and r.From.tag == t.From.tag and t2.server == t1.server</span>
        a = r.To.value.uri == t.To.value.uri
        <span class="p_word">if</span> _debug: <span class="p_word">print</span> r.From.value.uri, t.From.value.uri
        a = a <span class="p_word">and</span> (r.From.value.uri == t.From.value.uri)
        a = a <span class="p_word">and</span> (r[<span class="p_string">'Call-ID'</span>].value == t[<span class="p_string">'Call-ID'</span>].value)
        a = a <span class="p_word">and</span> (r.CSeq.value == t.CSeq.value)
        a = a <span class="p_word">and</span> (r.From.tag == t.From.tag)
        a = a <span class="p_word">and</span> (t2.server == t1.server)
        <span class="p_word">return</span> a
    
    <span class="p_word">def</span> createAck(self):
        <span class="p_triple">'''Create an ACK request (Message) in this client transaction, else None.'''</span>
        <span class="p_word">return</span> Message.createRequest(<span class="p_string">'ACK'</span>, str(self.request.uri), self.headers) <span class="p_word">if</span> self.request <span class="p_word">and</span> <span class="p_word">not</span> self.server <span class="p_word">else</span> <span class="p_word">None</span>
    
    <span class="p_word">def</span> createCancel(self):
        <span class="p_triple">'''Create a CANCEL request (Message) in this client transaction, else None.'''</span>
        m = Message.createRequest(<span class="p_string">'CANCEL'</span>, str(self.request.uri), self.headers) <span class="p_word">if</span> self.request <span class="p_word">and</span> <span class="p_word">not</span> self.server <span class="p_word">else</span> <span class="p_word">None</span>
        <span class="p_word">if</span> m <span class="p_word">and</span> self.request.Route: m.Route = self.request.Route
        <span class="p_word">if</span> m: m.Via = self.request.first(<span class="p_string">'Via'</span>) <span class="p_commentline"># only top Via included</span>
        <span class="p_word">return</span> m
        
    <span class="p_word">def</span> createResponse(self, response, responsetext):
        <span class="p_triple">'''Create a response (Message) in this server transaction, else None.'''</span>
        m = Message.createResponse(response, responsetext, <span class="p_word">None</span>, <span class="p_word">None</span>, self.request) <span class="p_word">if</span> self.request <span class="p_word">and</span> self.server <span class="p_word">else</span> <span class="p_word">None</span>
        <span class="p_word">if</span> response != <span class="p_number">100</span> <span class="p_word">and</span> <span class="p_string">'tag'</span> <span class="p_word">not</span> <span class="p_word">in</span> m.To: m.To[<span class="p_string">'tag'</span>] = self.tag <span class="p_commentline"># TODO: move this to UAS (?)</span>
        <span class="p_word">return</span> m
    
    <span class="p_word">def</span> startTimer(self, name, timeout):
        <span class="p_triple">'''Start a named timer with timeout (int).'''</span>
        <span class="p_word">if</span> timeout &gt; <span class="p_number">0</span>:
            <span class="p_word">if</span> name <span class="p_word">in</span> self.timers:
                timer = self.timers[name]
            <span class="p_word">else</span>:
                timer = self.timers[name] = self.stack.createTimer(self)
            timer.delay = timeout
            timer.start()

    <span class="p_word">def</span> stopTimers(self):
        <span class="p_triple">'''Stop all the named timers'''</span>
        <span class="p_word">for</span> v <span class="p_word">in</span> self.timers.values(): v.stop()
        <span class="p_word">del</span> self.timers

    <span class="p_word">def</span> timedout(self, timer):
        <span class="p_triple">'''Callback invoked by Timer returned by stack.createTimer().'''</span>
        <span class="p_word">if</span> timer.running: timer.stop()
        found = filter(<span class="p_word">lambda</span> x: self.timers[x] == timer, self.timers.keys())
        <span class="p_word">if</span> len(found):
            <span class="p_word">for</span> f <span class="p_word">in</span> found: <span class="p_word">del</span> self.timers[f]
            self.timeout(found[<span class="p_number">0</span>], timer.delay)


</PRE><DIV class="commentbox">From RFC3261 p.265<pre>A Table of Timer Values

   Table 4 summarizes the meaning and defaults of the various timers
   used by this specification.

Timer    Value            Section               Meaning
----------------------------------------------------------------------
T1       500ms default    Section 17.1.1.1     RTT Estimate
T2       4s               Section 17.1.2.2     The maximum retransmit
                                               interval for non-INVITE
                                               requests and INVITE
                                               responses
T4       5s               Section 17.1.2.2     Maximum duration a
                                               message will
                                               remain in the network
Timer A  initially T1     Section 17.1.1.2     INVITE request retransmit
                                               interval, for UDP only
Timer B  64*T1            Section 17.1.1.2     INVITE transaction
                                               timeout timer
Timer C  &amp;gt; 3min           Section 16.6         proxy INVITE transaction
                           bullet 11            timeout
Timer D  &amp;gt; 32s for UDP    Section 17.1.1.2     Wait time for response
         0s for TCP/SCTP                       retransmits
Timer E  initially T1     Section 17.1.2.2     non-INVITE request
                                               retransmit interval,
                                               UDP only
Timer F  64*T1            Section 17.1.2.2     non-INVITE transaction
                                               timeout timer
Timer G  initially T1     Section 17.2.1       INVITE response
                                               retransmit interval
Timer H  64*T1            Section 17.2.1       Wait time for
                                               ACK receipt
Timer I  T4 for UDP       Section 17.2.1       Wait time for
         0s for TCP/SCTP                       ACK retransmits
Timer J  64*T1 for UDP    Section 17.2.2       Wait time for
         0s for TCP/SCTP                       non-INVITE request
                                               retransmits
Timer K  T4 for UDP       Section 17.1.2.2     Wait time for
         0s for TCP/SCTP                       response retransmits
</pre></DIV><PRE>
<span class="p_word">class</span> Timer(object):
    <span class="p_triple">'''Various transaction timers as defined in <a href="http://www.rfc-editor.org/rfc/rfc3261.txt">RFC 3261</a>.'''</span>
    <span class="p_word">def</span> __init__(self, T1=<span class="p_number">500</span>, T2=<span class="p_number">4000</span>, T4=<span class="p_number">5000</span>):
        self.T1, self.T2, self.T4 = T1, T2, T4
    <span class="p_word">def</span> A(self): <span class="p_word">return</span> self.T1
    <span class="p_word">def</span> B(self): <span class="p_word">return</span> <span class="p_number">64</span>*self.T1
    <span class="p_word">def</span> D(self): <span class="p_word">return</span> max(<span class="p_number">64</span>*self.T1, <span class="p_number">32000</span>)
    <span class="p_word">def</span> I(self): <span class="p_word">return</span> self.T4
    A, B, D, E, F, G, H, I, J, K = map(<span class="p_word">lambda</span> x: property(x), [A, B, D, A, B, A, B, I, B, I])


</PRE><DIV class="commentbox">From RFC3261 p.130<pre>17.1.2 Non-INVITE Client Transaction

17.1.2.1 Overview of the non-INVITE Transaction

   Non-INVITE transactions do not make use of ACK.  They are simple
   request-response interactions.  For unreliable transports, requests
   are retransmitted at an interval which starts at T1 and doubles until
   it hits T2.  If a provisional response is received, retransmissions
   continue for unreliable transports, but at an interval of T2.  The
   server transaction retransmits the last response it sent, which can
   be a provisional or final response, only when a retransmission of the
   request is received.  This is why request retransmissions need to
   continue even after a provisional response; they are to ensure
   reliable delivery of the final response.
   Unlike an INVITE transaction, a non-INVITE transaction has no special
   handling for the 2xx response.  The result is that only a single 2xx
   response to a non-INVITE is ever delivered to a UAC.

17.1.2.2 Formal Description

   The state machine for the non-INVITE client transaction is shown in
   Figure 6.  It is very similar to the state machine for INVITE.

   The "Trying" state is entered when the TU initiates a new client
   transaction with a request.  When entering this state, the client
   transaction SHOULD set timer F to fire in 64*T1 seconds.  The request
   MUST be passed to the transport layer for transmission.  If an
   unreliable transport is in use, the client transaction MUST set timer
   E to fire in T1 seconds.  If timer E fires while still in this state,
   the timer is reset, but this time with a value of MIN(2*T1, T2).
   When the timer fires again, it is reset to a MIN(4*T1, T2).  This
   process continues so that retransmissions occur with an exponentially
   increasing interval that caps at T2.  The default value of T2 is 4s,
   and it represents the amount of time a non-INVITE server transaction
   will take to respond to a request, if it does not respond
   immediately.  For the default values of T1 and T2, this results in
   intervals of 500 ms, 1 s, 2 s, 4 s, 4 s, 4 s, etc.

   If Timer F fires while the client transaction is still in the
   "Trying" state, the client transaction SHOULD inform the TU about the
   timeout, and then it SHOULD enter the "Terminated" state.  If a
   provisional response is received while in the "Trying" state, the
   response MUST be passed to the TU, and then the client transaction
   SHOULD move to the "Proceeding" state.  If a final response (status
   codes 200-699) is received while in the "Trying" state, the response
   MUST be passed to the TU, and the client transaction MUST transition
   to the "Completed" state.

   If Timer E fires while in the "Proceeding" state, the request MUST be
   passed to the transport layer for retransmission, and Timer E MUST be
   reset with a value of T2 seconds.  If timer F fires while in the
   "Proceeding" state, the TU MUST be informed of a timeout, and the
   client transaction MUST transition to the terminated state.  If a
   final response (status codes 200-699) is received while in the
   "Proceeding" state, the response MUST be passed to the TU, and the
   client transaction MUST transition to the "Completed" state.

   Once the client transaction enters the "Completed" state, it MUST set
   Timer K to fire in T4 seconds for unreliable transports, and zero
   seconds for reliable transports.  The "Completed" state exists to
   buffer any additional response retransmissions that may be received
   (which is why the client transaction remains there only for
   unreliable transports).  T4 represents the amount of time the network
   will take to clear messages between client and server transactions.
   The default value of T4 is 5s.  A response is a retransmission when
   it matches the same transaction, using the rules specified in Section
   17.1.3.  If Timer K fires while in this state, the client transaction
   MUST transition to the "Terminated" state.

   Once the transaction is in the terminated state, it MUST be destroyed
   immediately.

17.1.3 Matching Responses to Client Transactions

   When the transport layer in the client receives a response, it has to
   determine which client transaction will handle the response, so that
   the processing of Sections 17.1.1 and 17.1.2 can take place.  The
   branch parameter in the top Via header field is used for this
   purpose.  A response matches a client transaction under two
   conditions:

      1.  If the response has the same value of the branch parameter in
          the top Via header field as the branch parameter in the top
          Via header field of the request that created the transaction.

      2.  If the method parameter in the CSeq header field matches the
          method of the request that created the transaction.  The
          method is needed since a CANCEL request constitutes a
          different transaction, but shares the same value of the branch
          parameter.

   If a request is sent via multicast, it is possible that it will
   generate multiple responses from different servers.  These responses
   will all have the same branch parameter in the topmost Via, but vary
   in the To tag.  The first response received, based on the rules
   above, will be used, and others will be viewed as retransmissions.
   That is not an error; multicast SIP provides only a rudimentary
   "single-hop-discovery-like" service that is limited to processing a
   single response.  See Section 18.1.1 for details.











17.1.4 Handling Transport Errors

                                   |Request from TU
                                   |send request
               Timer E             V
               send request  +-----------+
                   +---------|           |-------------------+
                   |         |  Trying   |  Timer F          |
                   +--------&amp;gt;|           |  or Transport Err.|
                             +-----------+  inform TU        |
                200-699         |  |                         |
                resp. to TU     |  |1xx                      |
                +---------------+  |resp. to TU              |
                |                  |                         |
                |   Timer E        V       Timer F           |
                |   send req +-----------+ or Transport Err. |
                |  +---------|           | inform TU         |
                |  |         |Proceeding |------------------&amp;gt;|
                |  +--------&amp;gt;|           |-----+             |
                |            +-----------+     |1xx          |
                |              |      ^        |resp to TU   |
                | 200-699      |      +--------+             |
                | resp. to TU  |                             |
                |              |                             |
                |              V                             |
                |            +-----------+                   |
                |            |           |                   |
                |            | Completed |                   |
                |            |           |                   |
                |            +-----------+                   |
                |              ^   |                         |
                |              |   | Timer K                 |
                +--------------+   | -                       |
                                   |                         |
                                   V                         |
             NOTE:           +-----------+                   |
                             |           |                   |
         transitions         | Terminated|&amp;lt;------------------+
         labeled with        |           |
         the event           +-----------+
         over the action
         to take

                 Figure 6: non-INVITE client transaction

   When the client transaction sends a request to the transport layer to
   be sent, the following procedures are followed if the transport layer
   indicates a failure.
   The client transaction SHOULD inform the TU that a transport failure
   has occurred, and the client transaction SHOULD transition directly
   to the "Terminated" state.  The TU will handle the failover
   mechanisms described in [4].

17.2 Server Transaction</pre></DIV><PRE>
<span class="p_word">class</span> ClientTransaction(Transaction):
    <span class="p_triple">'''Non-INVITE client transaction'''</span>
    <span class="p_word">def</span> __init__(self):
        Transaction.__init__(self, False)
    <span class="p_word">def</span> start(self):
        self.state = <span class="p_string">'trying'</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.transport.reliable: 
            self.startTimer(<span class="p_string">'E'</span>, self.timer.E)
        self.startTimer(<span class="p_string">'F'</span>, self.timer.F)
        self.stack.send(self.request, self.remote, self.transport)
        
    <span class="p_word">def</span> receivedResponse(self, response):
        <span class="p_word">if</span> response.is1xx:
            <span class="p_word">if</span> self.state == <span class="p_string">'trying'</span>:
                self.state = <span class="p_string">'proceeding'</span>
                self.app.receivedResponse(self, response)
            <span class="p_word">elif</span> self.state == <span class="p_string">'proceeding'</span>:
                self.app.receivedResponse(self, response)
        <span class="p_word">elif</span> response.isfinal:
            <span class="p_word">if</span> self.state == <span class="p_string">'trying'</span> <span class="p_word">or</span> self.state == <span class="p_string">'proceeding'</span>:
                self.state = <span class="p_string">'completed'</span>
                self.app.receivedResponse(self, response)
                <span class="p_word">if</span> <span class="p_word">not</span> self.transport.reliable:
                    self.startTimer(<span class="p_string">'K'</span>, self.timer.K)
                <span class="p_word">else</span>:
                    self.timeout(<span class="p_string">'K'</span>, <span class="p_number">0</span>)
        
    <span class="p_word">def</span> timeout(self, name, timeout):
        <span class="p_word">if</span> self.state == <span class="p_string">'trying'</span> <span class="p_word">or</span> self.state == <span class="p_string">'proceeding'</span>:
            <span class="p_word">if</span> name == <span class="p_string">'E'</span>:
                timeout = min(<span class="p_number">2</span>*timeout, self.timer.T2) <span class="p_word">if</span> self.state == <span class="p_string">'trying'</span> <span class="p_word">else</span> self.timer.T2 
                self.startTimer(<span class="p_string">'E'</span>, timeout)
                self.stack.send(self.request, self.remote, self.transport)
            <span class="p_word">elif</span> name == <span class="p_string">'F'</span>:
                self.state = <span class="p_string">'terminated'</span>
                self.app.timeout(self)
        <span class="p_word">elif</span> self.state == <span class="p_string">'completed'</span>:
            <span class="p_word">if</span> name == <span class="p_string">'K'</span>:
                self.state = <span class="p_string">'terminated'</span>
                
    <span class="p_word">def</span> error(self, error):
        <span class="p_word">if</span> self.state == <span class="p_string">'trying'</span> <span class="p_word">or</span> self.state == <span class="p_string">'proceeding'</span>:
            self.state = <span class="p_string">'terminated'</span>
            self.app.error(self, error)


</PRE><DIV class="commentbox">From RFC3261 p.137<pre>17.2.2 Non-INVITE Server Transaction

   The state machine for the non-INVITE server transaction is shown in
   Figure 8.

   The state machine is initialized in the "Trying" state and is passed
   a request other than INVITE or ACK when initialized.  This request is
   passed up to the TU.  Once in the "Trying" state, any further request
   retransmissions are discarded.  A request is a retransmission if it
   matches the same server transaction, using the rules specified in
   Section 17.2.3.

   While in the "Trying" state, if the TU passes a provisional response
   to the server transaction, the server transaction MUST enter the
   "Proceeding" state.  The response MUST be passed to the transport
   layer for transmission.  Any further provisional responses that are
   received from the TU while in the "Proceeding" state MUST be passed
   to the transport layer for transmission.  If a retransmission of the
   request is received while in the "Proceeding" state, the most
   recently sent provisional response MUST be passed to the transport
   layer for retransmission.  If the TU passes a final response (status
   codes 200-699) to the server while in the "Proceeding" state, the
   transaction MUST enter the "Completed" state, and the response MUST
   be passed to the transport layer for transmission.

   When the server transaction enters the "Completed" state, it MUST set
   Timer J to fire in 64*T1 seconds for unreliable transports, and zero
   seconds for reliable transports.  While in the "Completed" state, the
   server transaction MUST pass the final response to the transport
   layer for retransmission whenever a retransmission of the request is
   received.  Any other final responses passed by the TU to the server
   transaction MUST be discarded while in the "Completed" state.  The
   server transaction remains in this state until Timer J fires, at
   which point it MUST transition to the "Terminated" state.

   The server transaction MUST be destroyed the instant it enters the
   "Terminated" state.
17.2.3 Matching Requests to Server Transactions</pre></DIV><PRE>
</PRE><DIV class="commentbox">From RFC3261 p.140<pre>                                  |Request received
                                  |pass to TU
                                  V
                            +-----------+
                            |           |
                            | Trying    |-------------+
                            |           |             |
                            +-----------+             |200-699 from TU
                                  |                   |send response
                                  |1xx from TU        |
                                  |send response      |
                                  |                   |
               Request            V      1xx from TU  |
               send response+-----------+send response|
                   +--------|           |--------+    |
                   |        | Proceeding|        |    |
                   +-------&amp;gt;|           |&amp;lt;-------+    |
            +&amp;lt;--------------|           |             |
            |Trnsprt Err    +-----------+             |
            |Inform TU            |                   |
            |                     |                   |
            |                     |200-699 from TU    |
            |                     |send response      |
            |  Request            V                   |
            |  send response+-----------+             |
            |      +--------|           |             |
            |      |        | Completed |&amp;lt;------------+
            |      +-------&amp;gt;|           |
            +&amp;lt;--------------|           |
            |Trnsprt Err    +-----------+
            |Inform TU            |
            |                     |Timer J fires
            |                     |-
            |                     |
            |                     V
            |               +-----------+
            |               |           |
            +--------------&amp;gt;| Terminated|
                            |           |
                            +-----------+

                Figure 8: non-INVITE server transaction</pre></DIV><PRE>
<span class="p_word">class</span> ServerTransaction(Transaction):
    <span class="p_triple">'''Non-INVITE server transaction'''</span>
    <span class="p_word">def</span> __init__(self):
        Transaction.__init__(self, True)
    <span class="p_word">def</span> start(self):
        self.state = <span class="p_string">'trying'</span>
        self.app.receivedRequest(self, self.request)
    <span class="p_word">def</span> receivedRequest(self, request):
        <span class="p_word">if</span> self.request.method == request.method: <span class="p_commentline"># retransmitted</span>
            <span class="p_word">if</span> self.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> self.state == <span class="p_string">'completed'</span>:
                self.stack.send(self.lastResponse, self.remote, self.transport)
            <span class="p_word">elif</span> self.state == <span class="p_string">'trying'</span>:
                <span class="p_word">pass</span> <span class="p_commentline"># just ignore the retransmitted request</span>
    <span class="p_word">def</span> timeout(self, name, timeout):
        <span class="p_word">if</span> self.state == <span class="p_string">'completed'</span>:
            <span class="p_word">if</span> name == <span class="p_string">'J'</span>:
                self.state = <span class="p_string">'terminated'</span>
    <span class="p_word">def</span> error(self, error):
        <span class="p_word">if</span> self.state == <span class="p_string">'completed'</span>:
            self.state = <span class="p_string">'terminated'</span>
            self.app.error(self, error)
    <span class="p_word">def</span> sendResponse(self, response):
        self.lastResponse = response;
        <span class="p_word">if</span> response.is1xx:
            <span class="p_word">if</span> self.state == <span class="p_string">'trying'</span> <span class="p_word">or</span> self.state == <span class="p_string">'proceedings'</span>:
                self.state = <span class="p_string">'proceeding'</span>
                self.stack.send(response, self.remote, self.transport)
        <span class="p_word">elif</span> response.isfinal:
            <span class="p_word">if</span> self.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> self.state == <span class="p_string">'trying'</span>:
                self.state = <span class="p_string">'completed'</span>
                self.stack.send(response, self.remote, self.transport)
                <span class="p_word">if</span> <span class="p_word">not</span> self.transport.reliable: 
                    self.startTimer(<span class="p_string">'J'</span>, self.timer.J)
                <span class="p_word">else</span>:
                    self.timeout(<span class="p_string">'J'</span>, <span class="p_number">0</span>)


</PRE><DIV class="commentbox">From RFC3261 p.125<pre>17.1.1 INVITE Client Transaction

17.1.1.1 Overview of INVITE Transaction

   The INVITE transaction consists of a three-way handshake.  The client
   transaction sends an INVITE, the server transaction sends responses,
   and the client transaction sends an ACK.  For unreliable transports
   (such as UDP), the client transaction retransmits requests at an
   interval that starts at T1 seconds and doubles after every
   retransmission.  T1 is an estimate of the round-trip time (RTT), and
   it defaults to 500 ms.  Nearly all of the transaction timers
   described here scale with T1, and changing T1 adjusts their values.
   The request is not retransmitted over reliable transports.  After
   receiving a 1xx response, any retransmissions cease altogether, and
   the client waits for further responses.  The server transaction can
   send additional 1xx responses, which are not transmitted reliably by
   the server transaction.  Eventually, the server transaction decides
   to send a final response.  For unreliable transports, that response
   is retransmitted periodically, and for reliable transports, it is
   sent once.  For each final response that is received at the client
   transaction, the client transaction sends an ACK, the purpose of
   which is to quench retransmissions of the response.

17.1.1.2 Formal Description

   The state machine for the INVITE client transaction is shown in
   Figure 5.  The initial state, "calling", MUST be entered when the TU
   initiates a new client transaction with an INVITE request.  The
   client transaction MUST pass the request to the transport layer for
   transmission (see Section 18).  If an unreliable transport is being
   used, the client transaction MUST start timer A with a value of T1.
   If a reliable transport is being used, the client transaction SHOULD
   NOT start timer A (Timer A controls request retransmissions).  For
   any transport, the client transaction MUST start timer B with a value
   of 64*T1 seconds (Timer B controls transaction timeouts).

   When timer A fires, the client transaction MUST retransmit the
   request by passing it to the transport layer, and MUST reset the
   timer with a value of 2*T1.  The formal definition of retransmit

   within the context of the transaction layer is to take the message
   previously sent to the transport layer and pass it to the transport
   layer once more.

   When timer A fires 2*T1 seconds later, the request MUST be
   retransmitted again (assuming the client transaction is still in this
   state).  This process MUST continue so that the request is
   retransmitted with intervals that double after each transmission.
   These retransmissions SHOULD only be done while the client
   transaction is in the "calling" state.

   The default value for T1 is 500 ms.  T1 is an estimate of the RTT
   between the client and server transactions.  Elements MAY (though it
   is NOT RECOMMENDED) use smaller values of T1 within closed, private
   networks that do not permit general Internet connection.  T1 MAY be
   chosen larger, and this is RECOMMENDED if it is known in advance
   (such as on high latency access links) that the RTT is larger.
   Whatever the value of T1, the exponential backoffs on retransmissions
   described in this section MUST be used.

   If the client transaction is still in the "Calling" state when timer
   B fires, the client transaction SHOULD inform the TU that a timeout
   has occurred.  The client transaction MUST NOT generate an ACK.  The
   value of 64*T1 is equal to the amount of time required to send seven
   requests in the case of an unreliable transport.

   If the client transaction receives a provisional response while in
   the "Calling" state, it transitions to the "Proceeding" state. In the
   "Proceeding" state, the client transaction SHOULD NOT retransmit the
   request any longer. Furthermore, the provisional response MUST be
   passed to the TU.  Any further provisional responses MUST be passed
   up to the TU while in the "Proceeding" state.

   When in either the "Calling" or "Proceeding" states, reception of a
   response with status code from 300-699 MUST cause the client
   transaction to transition to "Completed".  The client transaction
   MUST pass the received response up to the TU, and the client
   transaction MUST generate an ACK request, even if the transport is
   reliable (guidelines for constructing the ACK from the response are
   given in Section 17.1.1.3) and then pass the ACK to the transport
   layer for transmission.  The ACK MUST be sent to the same address,
   port, and transport to which the original request was sent.  The
   client transaction SHOULD start timer D when it enters the
   "Completed" state, with a value of at least 32 seconds for unreliable
   transports, and a value of zero seconds for reliable transports.
   Timer D reflects the amount of time that the server transaction can
   remain in the "Completed" state when unreliable transports are used.
   This is equal to Timer H in the INVITE server transaction, whose
   default is 64*T1.  However, the client transaction does not know the
   value of T1 in use by the server transaction, so an absolute minimum
   of 32s is used instead of basing Timer D on T1.

   Any retransmissions of the final response that are received while in
   the "Completed" state MUST cause the ACK to be re-passed to the
   transport layer for retransmission, but the newly received response
   MUST NOT be passed up to the TU.  A retransmission of the response is
   defined as any response which would match the same client transaction
   based on the rules of Section 17.1.3.






































                               |INVITE from TU
             Timer A fires     |INVITE sent
             Reset A,          V                      Timer B fires
             INVITE sent +-----------+                or Transport Err.
               +---------|           |---------------+inform TU
               |         |  Calling  |               |
               +--------&amp;gt;|           |--------------&amp;gt;|
                         +-----------+ 2xx           |
                            |  |       2xx to TU     |
                            |  |1xx                  |
    300-699 +---------------+  |1xx to TU            |
   ACK sent |                  |                     |
resp. to TU |  1xx             V                     |
            |  1xx to TU  -----------+               |
            |  +---------|           |               |
            |  |         |Proceeding |--------------&amp;gt;|
            |  +--------&amp;gt;|           | 2xx           |
            |            +-----------+ 2xx to TU     |
            |       300-699    |                     |
            |       ACK sent,  |                     |
            |       resp. to TU|                     |
            |                  |                     |      NOTE:
            |  300-699         V                     |
            |  ACK sent  +-----------+Transport Err. |  transitions
            |  +---------|           |Inform TU      |  labeled with
            |  |         | Completed |--------------&amp;gt;|  the event
            |  +--------&amp;gt;|           |               |  over the action
            |            +-----------+               |  to take
            |              ^   |                     |
            |              |   | Timer D fires       |
            +--------------+   | -                   |
                               |                     |
                               V                     |
                         +-----------+               |
                         |           |               |
                         | Terminated|&amp;lt;--------------+
                         |           |
                         +-----------+

                 Figure 5: INVITE client transaction

   If timer D fires while the client transaction is in the "Completed"
   state, the client transaction MUST move to the terminated state.

   When in either the "Calling" or "Proceeding" states, reception of a
   2xx response MUST cause the client transaction to enter the
   "Terminated" state, and the response MUST be passed up to the TU.
   The handling of this response depends on whether the TU is a proxy
   core or a UAC core.  A UAC core will handle generation of the ACK for
   this response, while a proxy core will always forward the 200 (OK)
   upstream.  The differing treatment of 200 (OK) between proxy and UAC
   is the reason that handling of it does not take place in the
   transaction layer.

   The client transaction MUST be destroyed the instant it enters the
   "Terminated" state.  This is actually necessary to guarantee correct
   operation.  The reason is that 2xx responses to an INVITE are treated
   differently; each one is forwarded by proxies, and the ACK handling
   in a UAC is different.  Thus, each 2xx needs to be passed to a proxy
   core (so that it can be forwarded) and to a UAC core (so it can be
   acknowledged).  No transaction layer processing takes place.
   Whenever a response is received by the transport, if the transport
   layer finds no matching client transaction (using the rules of
   Section 17.1.3), the response is passed directly to the core.  Since
   the matching client transaction is destroyed by the first 2xx,
   subsequent 2xx will find no match and therefore be passed to the
   core.</pre></DIV><PRE>
<span class="p_word">class</span> InviteClientTransaction(Transaction):
    <span class="p_triple">'''INVITE client transaction'''</span>
    <span class="p_word">def</span> __init__(self):
        Transaction.__init__(self, False)
    <span class="p_word">def</span> start(self):
        self.state = <span class="p_string">'calling'</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.transport.reliable: 
            self.startTimer(<span class="p_string">'A'</span>, self.timer.A)
        self.startTimer(<span class="p_string">'B'</span>, self.timer.B)
        self.stack.send(self.request, self.remote, self.transport)
         
    <span class="p_word">def</span> receivedResponse(self, response):
        <span class="p_word">if</span> response.is1xx:
            <span class="p_word">if</span> self.state == <span class="p_string">'calling'</span>:
                self.state = <span class="p_string">'proceeding'</span>
                self.app.receivedResponse(self, response)
            <span class="p_word">elif</span> self.state == <span class="p_string">'proceeding'</span>:
                self.app.receivedResponse(self, response)
        <span class="p_word">elif</span> response.is2xx:
            <span class="p_word">if</span> self.state == <span class="p_string">'calling'</span> <span class="p_word">or</span> self.state == <span class="p_string">'proceeding'</span>:
                self.state = <span class="p_string">'terminated'</span>
                self.app.receivedResponse(self, response)
        <span class="p_word">else</span>: <span class="p_commentline"># failure</span>
            <span class="p_word">if</span> self.state == <span class="p_string">'calling'</span> <span class="p_word">or</span> self.state == <span class="p_string">'proceeding'</span>:
                self.state = <span class="p_string">'completed'</span>
                self.stack.send(self.createAck(response), self.remote, self.transport)
                self.app.receivedResponse(self, response)
                <span class="p_word">if</span> <span class="p_word">not</span> self.transport.reliable:
                    self.startTimer(<span class="p_string">'D'</span>, self.timer.D)
                <span class="p_word">else</span>:
                    self.timeout(<span class="p_string">'D'</span>, <span class="p_number">0</span>)
            <span class="p_word">elif</span> self.state == <span class="p_string">'completed'</span>:
                self.stack.send(self.createAck(response), self.remote, self.transport)
                
    <span class="p_word">def</span> timeout(self, name, timeout):
        <span class="p_word">if</span> self.state == <span class="p_string">'calling'</span>:
            <span class="p_word">if</span> name == <span class="p_string">'A'</span>:
                self.startTimer(<span class="p_string">'A'</span>, <span class="p_number">2</span>*timeout)
                self.stack.send(self.request, self.remote, self.transport)
            <span class="p_word">elif</span> name == <span class="p_string">'B'</span>:
                self.state = <span class="p_string">'terminated'</span>
                self.app.timeout(self)
        <span class="p_word">elif</span> self.state == <span class="p_string">'completed'</span>:
            <span class="p_word">if</span> name == <span class="p_string">'D'</span>:
                self.state = <span class="p_string">'terminated'</span>
                
    <span class="p_word">def</span> error(self, error):
        <span class="p_word">if</span> self.state == <span class="p_string">'calling'</span> <span class="p_word">or</span> self.state == <span class="p_string">'completed'</span>:
            self.state = <span class="p_string">'terminated'</span>
            self.app.error(self, error)
        

</PRE><DIV class="commentbox">From RFC3261 p.129<pre>17.1.1.3 Construction of the ACK Request

   This section specifies the construction of ACK requests sent within
   the client transaction.  A UAC core that generates an ACK for 2xx
   MUST instead follow the rules described in Section 13.

   The ACK request constructed by the client transaction MUST contain
   values for the Call-ID, From, and Request-URI that are equal to the
   values of those header fields in the request passed to the transport
   by the client transaction (call this the "original request").  The To
   header field in the ACK MUST equal the To header field in the
   response being acknowledged, and therefore will usually differ from
   the To header field in the original request by the addition of the
   tag parameter.  The ACK MUST contain a single Via header field, and
   this MUST be equal to the top Via header field of the original
   request.  The CSeq header field in the ACK MUST contain the same
   value for the sequence number as was present in the original request,
   but the method parameter MUST be equal to "ACK".










   If the INVITE request whose response is being acknowledged had Route
   header fields, those header fields MUST appear in the ACK.  This is
   to ensure that the ACK can be routed properly through any downstream
   stateless proxies.

   Although any request MAY contain a body, a body in an ACK is special
   since the request cannot be rejected if the body is not understood.
   Therefore, placement of bodies in ACK for non-2xx is NOT RECOMMENDED,
   but if done, the body types are restricted to any that appeared in
   the INVITE, assuming that the response to the INVITE was not 415.  If
   it was, the body in the ACK MAY be any type listed in the Accept
   header field in the 415.</pre></DIV><PRE>
    <span class="p_word">def</span> createAck(self, response):
        <span class="p_word">if</span> <span class="p_word">not</span> self.request: <span class="p_word">raise</span> ValueError, <span class="p_string">'No transaction request found'</span>
        m = Message.createRequest(<span class="p_string">'ACK'</span>, str(self.request.uri))
        m[<span class="p_string">'Call-ID'</span>] = self.request[<span class="p_string">'Call-ID'</span>]
        m.From   = self.request.From
        m.To     = response.To <span class="p_word">if</span> response <span class="p_word">else</span> self.request.To
        m.Via    = self.request.first(<span class="p_string">"Via"</span>) <span class="p_commentline"># only top Via</span>
        m.CSeq   = Header(str(self.request.CSeq.number) + <span class="p_string">' ACK'</span>, <span class="p_string">'CSeq'</span>) 
        <span class="p_word">if</span> self.request.Route: m.Route = self.request.Route
        <span class="p_word">return</span> m;


</PRE><DIV class="commentbox">From RFC3261 p.134<pre>17.2.1 INVITE Server Transaction

   The state diagram for the INVITE server transaction is shown in
   Figure 7.

   When a server transaction is constructed for a request, it enters the
   "Proceeding" state.  The server transaction MUST generate a 100
   (Trying) response unless it knows that the TU will generate a
   provisional or final response within 200 ms, in which case it MAY
   generate a 100 (Trying) response.  This provisional response is
   needed to quench request retransmissions rapidly in order to avoid
   network congestion.  The 100 (Trying) response is constructed
   according to the procedures in Section 8.2.6, except that the
   insertion of tags in the To header field of the response (when none
   was present in the request) is downgraded from MAY to SHOULD NOT.
   The request MUST be passed to the TU.

   The TU passes any number of provisional responses to the server
   transaction.  So long as the server transaction is in the
   "Proceeding" state, each of these MUST be passed to the transport
   layer for transmission.  They are not sent reliably by the
   transaction layer (they are not retransmitted by it) and do not cause
   a change in the state of the server transaction.  If a request
   retransmission is received while in the "Proceeding" state, the most
   recent provisional response that was received from the TU MUST be
   passed to the transport layer for retransmission.  A request is a
   retransmission if it matches the same server transaction based on the
   rules of Section 17.2.3.

   If, while in the "Proceeding" state, the TU passes a 2xx response to
   the server transaction, the server transaction MUST pass this
   response to the transport layer for transmission.  It is not
   retransmitted by the server transaction; retransmissions of 2xx
   responses are handled by the TU.  The server transaction MUST then
   transition to the "Terminated" state.

   While in the "Proceeding" state, if the TU passes a response with
   status code from 300 to 699 to the server transaction, the response
   MUST be passed to the transport layer for transmission, and the state
   machine MUST enter the "Completed" state.  For unreliable transports,
   timer G is set to fire in T1 seconds, and is not set to fire for
   reliable transports.

      This is a change from RFC 2543, where responses were always
      retransmitted, even over reliable transports.

   When the "Completed" state is entered, timer H MUST be set to fire in
   64*T1 seconds for all transports.  Timer H determines when the server
   transaction abandons retransmitting the response.  Its value is
   chosen to equal Timer B, the amount of time a client transaction will
   continue to retry sending a request.  If timer G fires, the response
   is passed to the transport layer once more for retransmission, and
   timer G is set to fire in MIN(2*T1, T2) seconds.  From then on, when
   timer G fires, the response is passed to the transport again for
   transmission, and timer G is reset with a value that doubles, unless
   that value exceeds T2, in which case it is reset with the value of
   T2.  This is identical to the retransmit behavior for requests in the
   "Trying" state of the non-INVITE client transaction.  Furthermore,
   while in the "Completed" state, if a request retransmission is
   received, the server SHOULD pass the response to the transport for
   retransmission.

   If an ACK is received while the server transaction is in the
   "Completed" state, the server transaction MUST transition to the
   "Confirmed" state.  As Timer G is ignored in this state, any
   retransmissions of the response will cease.

   If timer H fires while in the "Completed" state, it implies that the
   ACK was never received.  In this case, the server transaction MUST
   transition to the "Terminated" state, and MUST indicate to the TU
   that a transaction failure has occurred.









                               |INVITE
                               |pass INV to TU
            INVITE             V send 100 if TU won't in 200ms
            send response+-----------+
                +--------|           |--------+101-199 from TU
                |        | Proceeding|        |send response
                +-------&amp;gt;|           |&amp;lt;-------+
                         |           |          Transport Err.
                         |           |          Inform TU
                         |           |---------------&amp;gt;+
                         +-----------+                |
            300-699 from TU |     |2xx from TU        |
            send response   |     |send response      |
                            |     +------------------&amp;gt;+
                            |                         |
            INVITE          V          Timer G fires  |
            send response+-----------+ send response  |
                +--------|           |--------+       |
                |        | Completed |        |       |
                +-------&amp;gt;|           |&amp;lt;-------+       |
                         +-----------+                |
                            |     |                   |
                        ACK |     |                   |
                        -   |     +------------------&amp;gt;+
                            |        Timer H fires    |
                            V        or Transport Err.|
                         +-----------+  Inform TU     |
                         |           |                |
                         | Confirmed |                |
                         |           |                |
                         +-----------+                |
                               |                      |
                               |Timer I fires         |
                               |-                     |
                               |                      |
                               V                      |
                         +-----------+                |
                         |           |                |
                         | Terminated|&amp;lt;---------------+
                         |           |
                         +-----------+

              Figure 7: INVITE server transaction





   The purpose of the "Confirmed" state is to absorb any additional ACK
   messages that arrive, triggered from retransmissions of the final
   response.  When this state is entered, timer I is set to fire in T4
   seconds for unreliable transports, and zero seconds for reliable
   transports.  Once timer I fires, the server MUST transition to the
   "Terminated" state.

   Once the transaction is in the "Terminated" state, it MUST be
   destroyed immediately.  As with client transactions, this is needed
   to ensure reliability of the 2xx responses to INVITE.</pre></DIV><PRE>
<span class="p_commentline"># I modified to also have a trying state needed for proxy mode when 100 is not sent immediately.</span>
<span class="p_word">class</span> InviteServerTransaction(Transaction):
    <span class="p_triple">'''INVITE server transaction'''</span>
    <span class="p_word">def</span> __init__(self):
        Transaction.__init__(self, True)
    <span class="p_word">def</span> start(self):
        self.state = <span class="p_string">'proceeding'</span>
        self.sendResponse(self.createResponse(<span class="p_number">100</span>, <span class="p_string">'Trying'</span>))
        self.app.receivedRequest(self, self.request)
    <span class="p_word">def</span> receivedRequest(self, request):
        <span class="p_word">if</span> self.request.method == request.method: <span class="p_commentline"># retransmitted</span>
            <span class="p_word">if</span> self.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> self.state == <span class="p_string">'completed'</span>:
                self.stack.send(self.lastResponse, self.remote, self.transport)
        <span class="p_word">elif</span> request.method == <span class="p_string">'ACK'</span>:
            <span class="p_word">if</span> self.state == <span class="p_string">'completed'</span>:
                self.state = <span class="p_string">'confirmed'</span>
                <span class="p_word">if</span> <span class="p_word">not</span> self.transport.reliable:
                    self.startTimer(<span class="p_string">'I'</span>, self.timer.I)
                <span class="p_word">else</span>:
                    self.timeout(<span class="p_string">'I'</span>, <span class="p_number">0</span>)
            <span class="p_word">elif</span> self.state == <span class="p_string">'confirmed'</span>:
                <span class="p_word">pass</span>  <span class="p_commentline"># ignore the retransmitted ACK</span>
    <span class="p_word">def</span> timeout(self, name, timeout):
        <span class="p_word">if</span> self.state == <span class="p_string">'completed'</span>:
            <span class="p_word">if</span> name == <span class="p_string">'G'</span>:
                self.startTimer(<span class="p_string">'G'</span>, min(<span class="p_number">2</span>*timeout, self.timer.T2))
                self.stack.send(self.lastResponse, self.remote, self.transport)
            <span class="p_word">elif</span> name == <span class="p_string">'H'</span>:
                self.state = <span class="p_string">'terminated'</span>
                self.app.timeout(self)
        <span class="p_word">elif</span> self.state == <span class="p_string">'confirmed'</span>:
            <span class="p_word">if</span> name == <span class="p_string">'I'</span>:
                self.state = <span class="p_string">'terminated'</span>
                
    <span class="p_word">def</span> error(self, error):
        <span class="p_word">if</span> self.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> self.state == <span class="p_string">'trying'</span> <span class="p_word">or</span> self.state == <span class="p_string">'confirmed'</span>:
            self.state = <span class="p_string">'terminated'</span>
            self.app.error(self, error)
    <span class="p_word">def</span> sendResponse(self, response):
        self.lastResponse = response
        <span class="p_word">if</span> response.is1xx:
            <span class="p_word">if</span> self.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> self.state == <span class="p_string">'trying'</span>:
                self.stack.send(response, self.remote, self.transport)
        <span class="p_word">elif</span> response.is2xx:
            <span class="p_word">if</span> self.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> self.state == <span class="p_string">'trying'</span>:
                self.state = <span class="p_string">'terminated'</span>
                self.stack.send(response, self.remote, self.transport)
        <span class="p_word">else</span>: <span class="p_commentline"># failure</span>
            <span class="p_word">if</span> self.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> self.state == <span class="p_string">'trying'</span>:
                self.state = <span class="p_string">'completed'</span>
                <span class="p_word">if</span> <span class="p_word">not</span> self.transport.reliable: 
                    self.startTimer(<span class="p_string">'G'</span>, self.timer.G)
                self.startTimer(<span class="p_string">'H'</span>, self.timer.H)
                self.stack.send(response, self.remote, self.transport)


<span class="p_word">if</span> __name__ == <span class="p_string">'__main__'</span>:
    m = Message(<span class="p_string">'INVITE sip:kundan@example.net SIP/2.0\r\n'</span>
              + <span class="p_string">'CSeq: 1 INVITE\r\n'</span>
              + <span class="p_string">'To: sip:kundan@example.net\r\n'</span>
              + <span class="p_string">'From: sip:sanjayc77@example.net\r\n'</span>
              + <span class="p_string">'Call-ID: 783713917681\r\n'</span>
              + <span class="p_string">'\r\n'</span>)
    <span class="p_word">print</span> Transaction.createBranch(m, True)

<span class="p_commentline">#---------------------------UserAgent and Dialog---------------------------</span>


</PRE><DIV class="commentbox">From RFC3261 p.34<pre>8 General User Agent Behavior

   A user agent represents an end system.  It contains a user agent
   client (UAC), which generates requests, and a user agent server
   (UAS), which responds to them.  A UAC is capable of generating a
   request based on some external stimulus (the user clicking a button,
   or a signal on a PSTN line) and processing a response.  A UAS is
   capable of receiving a request and generating a response based on
   user input, external stimulus, the result of a program execution, or
   some other mechanism.

   When a UAC sends a request, the request passes through some number of
   proxy servers, which forward the request towards the UAS. When the
   UAS generates a response, the response is forwarded towards the UAC.

   UAC and UAS procedures depend strongly on two factors.  First, based
   on whether the request or response is inside or outside of a dialog,
   and second, based on the method of a request.  Dialogs are discussed
   thoroughly in Section 12; they represent a peer-to-peer relationship
   between user agents and are established by specific SIP methods, such
   as INVITE.</pre></DIV><PRE>
<span class="p_word">class</span> UserAgent(object):
    <span class="p_triple">'''Represents both UAS and UAC.'''</span>
    <span class="p_word">def</span> __init__(self, stack, request=<span class="p_word">None</span>, server=<span class="p_word">None</span>):
        <span class="p_triple">'''Construct as UAS (if incoming request Message is supplied) or UAC.'''</span>
        self.stack, self.request = stack, request
        self.server = server <span class="p_word">if</span> server != <span class="p_word">None</span> <span class="p_word">else</span> (request != <span class="p_word">None</span>)
        self.transaction, self.cancelRequest = <span class="p_word">None</span>, <span class="p_word">None</span>

        self.callId = request[<span class="p_string">'Call-ID'</span>].value <span class="p_word">if</span> request <span class="p_word">and</span> request[<span class="p_string">'Call-ID'</span>] <span class="p_word">else</span> stack.newCallId
        self.remoteParty = request.From.value <span class="p_word">if</span> request <span class="p_word">and</span> request.From <span class="p_word">else</span> <span class="p_word">None</span>
        self.localParty = request.To.value <span class="p_word">if</span> request <span class="p_word">and</span> request.To <span class="p_word">else</span> <span class="p_word">None</span>
        self.localTag, self.remoteTag  = stack.tag + str(random.randint(<span class="p_number">0</span>,<span class="p_number">10</span>*<span class="p_number">10</span>)), <span class="p_word">None</span>
        self.subject = request.Subject.value <span class="p_word">if</span> request <span class="p_word">and</span> request.Subject <span class="p_word">else</span> <span class="p_word">None</span>
        self.secure = (request <span class="p_word">and</span> request.uri.scheme == <span class="p_string">'sips'</span>)
        self.maxForwards, self.routeSet = <span class="p_number">70</span>, [] 
        self.localTarget, self.remoteTarget, self.remoteCandidates = <span class="p_word">None</span>, <span class="p_word">None</span>, <span class="p_word">None</span>
        self.localSeq, self.remoteSeq = <span class="p_number">0</span>, <span class="p_number">0</span>
        self.contact = Address(str(stack.uri))
        <span class="p_word">if</span> self.localParty <span class="p_word">and</span> self.localParty.uri.user: self.contact.uri.user = self.localParty.uri.user 
        
        self.autoack = True<span class="p_commentline"># whether to send an ACK to 200 OK of INVITE automatically or let application send it.</span>
        self.auth = dict() <span class="p_commentline"># to store authentication context</span>

    <span class="p_word">def</span> __repr__(self):
        <span class="p_triple">'''Just a textual representation of the UserAgent'''</span>
        <span class="p_word">return</span> <span class="p_string">'&lt;%s call-id=%s&gt;'</span>%(isinstance(self, Dialog) <span class="p_word">and</span> <span class="p_string">'Dialog'</span> <span class="p_word">or</span> <span class="p_string">'UserAgent'</span>, self.callId)
    
    <span class="p_word">def</span> createTransaction(self, request):
        <span class="p_triple">'''Create a new server transaction for the UAS request. A stateless proxy may not create a transaction.'''</span>
        <span class="p_word">return</span> Transaction.createServer(self.stack, self, request, self.stack.transport, self.stack.tag)
    

</PRE><DIV class="commentbox">From RFC3261 p.35<pre>8.1.1 Generating the Request

   A valid SIP request formulated by a UAC MUST, at a minimum, contain
   the following header fields: To, From, CSeq, Call-ID, Max-Forwards,
   and Via; all of these header fields are mandatory in all SIP
   requests.  These six header fields are the fundamental building
   blocks of a SIP message, as they jointly provide for most of the
   critical message routing services including the addressing of
   messages, the routing of responses, limiting message propagation,
   ordering of messages, and the unique identification of transactions.
   These header fields are in addition to the mandatory request line,
   which contains the method, Request-URI, and SIP version.

   Examples of requests sent outside of a dialog include an INVITE to
   establish a session (Section 13) and an OPTIONS to query for
   capabilities (Section 11).

8.1.1.1 Request-URI

   The initial Request-URI of the message SHOULD be set to the value of
   the URI in the To field.  One notable exception is the REGISTER
   method; behavior for setting the Request-URI of REGISTER is given in
   Section 10.  It may also be undesirable for privacy reasons or
   convenience to set these fields to the same value (especially if the
   originating UA expects that the Request-URI will be changed during
   transit).

   In some special circumstances, the presence of a pre-existing route
   set can affect the Request-URI of the message.  A pre-existing route
   set is an ordered set of URIs that identify a chain of servers, to
   which a UAC will send outgoing requests that are outside of a dialog.
   Commonly, they are configured on the UA by a user or service provider
   manually, or through some other non-SIP mechanism.  When a provider
   wishes to configure a UA with an outbound proxy, it is RECOMMENDED
   that this be done by providing it with a pre-existing route set with
   a single URI, that of the outbound proxy.

   When a pre-existing route set is present, the procedures for
   populating the Request-URI and Route header field detailed in Section
   12.2.1.1 MUST be followed (even though there is no dialog), using the
   desired Request-URI as the remote target URI.



8.1.1.2 To

   The To header field first and foremost specifies the desired
   "logical" recipient of the request, or the address-of-record of the
   user or resource that is the target of this request.  This may or may
   not be the ultimate recipient of the request.  The To header field
   MAY contain a SIP or SIPS URI, but it may also make use of other URI
   schemes (the tel URL (RFC 2806 [9]), for example) when appropriate.
   All SIP implementations MUST support the SIP URI scheme.  Any
   implementation that supports TLS MUST support the SIPS URI scheme.
   The To header field allows for a display name.

   A UAC may learn how to populate the To header field for a particular
   request in a number of ways.  Usually the user will suggest the To
   header field through a human interface, perhaps inputting the URI
   manually or selecting it from some sort of address book.  Frequently,
   the user will not enter a complete URI, but rather a string of digits
   or letters (for example, "bob").  It is at the discretion of the UA
   to choose how to interpret this input.  Using the string to form the
   user part of a SIP URI implies that the UA wishes the name to be
   resolved in the domain to the right-hand side (RHS) of the at-sign in
   the SIP URI (for instance, sip:bob@example.com).  Using the string to
   form the user part of a SIPS URI implies that the UA wishes to
   communicate securely, and that the name is to be resolved in the
   domain to the RHS of the at-sign.  The RHS will frequently be the
   home domain of the requestor, which allows for the home domain to
   process the outgoing request.  This is useful for features like
   "speed dial" that require interpretation of the user part in the home
   domain.  The tel URL may be used when the UA does not wish to specify
   the domain that should interpret a telephone number that has been
   input by the user.  Rather, each domain through which the request
   passes would be given that opportunity.  As an example, a user in an
   airport might log in and send requests through an outbound proxy in
   the airport.  If they enter "411" (this is the phone number for local
   directory assistance in the United States), that needs to be
   interpreted and processed by the outbound proxy in the airport, not
   the user's home domain.  In this case, tel:411 would be the right
   choice.

   A request outside of a dialog MUST NOT contain a To tag; the tag in
   the To field of a request identifies the peer of the dialog.  Since
   no dialog is established, no tag is present.

   For further information on the To header field, see Section 20.39.
   The following is an example of a valid To header field:

      To: Carol &amp;lt;sip:carol@chicago.com&amp;gt;

8.1.1.3 From

   The From header field indicates the logical identity of the initiator
   of the request, possibly the user's address-of-record.  Like the To
   header field, it contains a URI and optionally a display name.  It is
   used by SIP elements to determine which processing rules to apply to
   a request (for example, automatic call rejection).  As such, it is
   very important that the From URI not contain IP addresses or the FQDN
   of the host on which the UA is running, since these are not logical
   names.

   The From header field allows for a display name.  A UAC SHOULD use
   the display name "Anonymous", along with a syntactically correct, but
   otherwise meaningless URI (like sip:thisis@anonymous.invalid), if the
   identity of the client is to remain hidden.

   Usually, the value that populates the From header field in requests
   generated by a particular UA is pre-provisioned by the user or by the
   administrators of the user's local domain.  If a particular UA is
   used by multiple users, it might have switchable profiles that
   include a URI corresponding to the identity of the profiled user.
   Recipients of requests can authenticate the originator of a request
   in order to ascertain that they are who their From header field
   claims they are (see Section 22 for more on authentication).

   The From field MUST contain a new "tag" parameter, chosen by the UAC.
   See Section 19.3 for details on choosing a tag.

   For further information on the From header field, see Section 20.20.
   Examples:

      From: "Bob" &amp;lt;sips:bob@biloxi.com&amp;gt; ;tag=a48s
      From: sip:+12125551212@phone2net.com;tag=887s
      From: Anonymous &amp;lt;sip:c8oqz84zk7z@privacy.org&amp;gt;;tag=hyh8

8.1.1.4 Call-ID

   The Call-ID header field acts as a unique identifier to group
   together a series of messages.  It MUST be the same for all requests
   and responses sent by either UA in a dialog.  It SHOULD be the same
   in each registration from a UA.

   In a new request created by a UAC outside of any dialog, the Call-ID
   header field MUST be selected by the UAC as a globally unique
   identifier over space and time unless overridden by method-specific
   behavior.  All SIP UAs must have a means to guarantee that the Call-
   ID header fields they produce will not be inadvertently generated by
   any other UA.  Note that when requests are retried after certain
   failure responses that solicit an amendment to a request (for
   example, a challenge for authentication), these retried requests are
   not considered new requests, and therefore do not need new Call-ID
   header fields; see Section 8.1.3.5.

   Use of cryptographically random identifiers (RFC 1750 [12]) in the
   generation of Call-IDs is RECOMMENDED.  Implementations MAY use the
   form "localid@host".  Call-IDs are case-sensitive and are simply
   compared byte-by-byte.

      Using cryptographically random identifiers provides some
      protection against session hijacking and reduces the likelihood of
      unintentional Call-ID collisions.

   No provisioning or human interface is required for the selection of
   the Call-ID header field value for a request.

   For further information on the Call-ID header field, see Section
   20.8.

   Example:

      Call-ID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6@foo.bar.com

8.1.1.5 CSeq

   The CSeq header field serves as a way to identify and order
   transactions.  It consists of a sequence number and a method.  The
   method MUST match that of the request.  For non-REGISTER requests
   outside of a dialog, the sequence number value is arbitrary.  The
   sequence number value MUST be expressible as a 32-bit unsigned
   integer and MUST be less than 2**31.  As long as it follows the above
   guidelines, a client may use any mechanism it would like to select
   CSeq header field values.

   Section 12.2.1.1 discusses construction of the CSeq for requests
   within a dialog.

   Example:

      CSeq: 4711 INVITE







8.1.1.6 Max-Forwards

   The Max-Forwards header field serves to limit the number of hops a
   request can transit on the way to its destination.  It consists of an
   integer that is decremented by one at each hop.  If the Max-Forwards
   value reaches 0 before the request reaches its destination, it will
   be rejected with a 483(Too Many Hops) error response.

   A UAC MUST insert a Max-Forwards header field into each request it
   originates with a value that SHOULD be 70.  This number was chosen to
   be sufficiently large to guarantee that a request would not be
   dropped in any SIP network when there were no loops, but not so large
   as to consume proxy resources when a loop does occur.  Lower values
   should be used with caution and only in networks where topologies are
   known by the UA.

8.1.1.7 Via

   The Via header field indicates the transport used for the transaction
   and identifies the location where the response is to be sent.  A Via
   header field value is added only after the transport that will be
   used to reach the next hop has been selected (which may involve the
   usage of the procedures in [4]).

   When the UAC creates a request, it MUST insert a Via into that
   request.  The protocol name and protocol version in the header field
   MUST be SIP and 2.0, respectively.  The Via header field value MUST
   contain a branch parameter.  This parameter is used to identify the
   transaction created by that request.  This parameter is used by both
   the client and the server.

   The branch parameter value MUST be unique across space and time for
   all requests sent by the UA.  The exceptions to this rule are CANCEL
   and ACK for non-2xx responses.  As discussed below, a CANCEL request
   will have the same value of the branch parameter as the request it
   cancels.  As discussed in Section 17.1.1.3, an ACK for a non-2xx
   response will also have the same branch ID as the INVITE whose
   response it acknowledges.

      The uniqueness property of the branch ID parameter, to facilitate
      its use as a transaction ID, was not part of RFC 2543.

   The branch ID inserted by an element compliant with this
   specification MUST always begin with the characters "z9hG4bK".  These
   7 characters are used as a magic cookie (7 is deemed sufficient to
   ensure that an older RFC 2543 implementation would not pick such a
   value), so that servers receiving the request can determine that the
   branch ID was constructed in the fashion described by this
   specification (that is, globally unique).  Beyond this requirement,
   the precise format of the branch token is implementation-defined.

   The Via header maddr, ttl, and sent-by components will be set when
   the request is processed by the transport layer (Section 18).

   Via processing for proxies is described in Section 16.6 Item 8 and
   Section 16.7 Item 3.

8.1.1.8 Contact

   The Contact header field provides a SIP or SIPS URI that can be used
   to contact that specific instance of the UA for subsequent requests.
   The Contact header field MUST be present and contain exactly one SIP
   or SIPS URI in any request that can result in the establishment of a
   dialog.  For the methods defined in this specification, that includes
   only the INVITE request.  For these requests, the scope of the
   Contact is global.  That is, the Contact header field value contains
   the URI at which the UA would like to receive requests, and this URI
   MUST be valid even if used in subsequent requests outside of any
   dialogs.

   If the Request-URI or top Route header field value contains a SIPS
   URI, the Contact header field MUST contain a SIPS URI as well.

   For further information on the Contact header field, see Section
   20.10.

8.1.1.9 Supported and Require

   If the UAC supports extensions to SIP that can be applied by the
   server to the response, the UAC SHOULD include a Supported header
   field in the request listing the option tags (Section 19.2) for those
   extensions.

   The option tags listed MUST only refer to extensions defined in
   standards-track RFCs.  This is to prevent servers from insisting that
   clients implement non-standard, vendor-defined features in order to
   receive service.  Extensions defined by experimental and
   informational RFCs are explicitly excluded from usage with the
   Supported header field in a request, since they too are often used to
   document vendor-defined extensions.

   If the UAC wishes to insist that a UAS understand an extension that
   the UAC will apply to the request in order to process the request, it
   MUST insert a Require header field into the request listing the
   option tag for that extension.  If the UAC wishes to apply an
   extension to the request and insist that any proxies that are
   traversed understand that extension, it MUST insert a Proxy-Require
   header field into the request listing the option tag for that
   extension.

   As with the Supported header field, the option tags in the Require
   and Proxy-Require header fields MUST only refer to extensions defined
   in standards-track RFCs.

8.1.1.10 Additional Message Components

   After a new request has been created, and the header fields described
   above have been properly constructed, any additional optional header
   fields are added, as are any header fields specific to the method.

   SIP requests MAY contain a MIME-encoded message-body.  Regardless of
   the type of body that a request contains, certain header fields must
   be formulated to characterize the contents of the body.  For further
   information on these header fields, see Sections 20.11 through 20.15.</pre></DIV><PRE>
    <span class="p_word">def</span> createRequest(self, method, content=<span class="p_word">None</span>, contentType=<span class="p_word">None</span>):
        <span class="p_triple">'''Create new UAC request.'''</span>
        self.server = False
        <span class="p_word">if</span> <span class="p_word">not</span> self.remoteParty: <span class="p_word">raise</span> ValueError, <span class="p_string">'No remoteParty for UAC'</span> 
        <span class="p_word">if</span> <span class="p_word">not</span> self.localParty: self.localParty = Address(<span class="p_string">'"Anonymous" &lt;sip:anonymous@anonymous.invalid&gt;'</span>)
        uri = URI(str(self.remoteTarget <span class="p_word">if</span> self.remoteTarget <span class="p_word">else</span> self.remoteParty.uri)) <span class="p_commentline"># TODO: use original URI for ACK</span>
        <span class="p_word">if</span> method == <span class="p_string">'REGISTER'</span>: uri.user = <span class="p_word">None</span> <span class="p_commentline"># no uri.user in REGISTER</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.secure <span class="p_word">and</span> uri.secure: self.secure = True
        <span class="p_word">if</span> method != <span class="p_string">'ACK'</span> <span class="p_word">and</span> method != <span class="p_string">'CANCEL'</span>: self.localSeq = self.localSeq + <span class="p_number">1</span>

        <span class="p_commentline"># initial headers</span>
        To = Header(str(self.remoteParty), <span class="p_string">'To'</span>)
        To.value.uri.secure = self.secure
        From = Header(str(self.localParty), <span class="p_string">'From'</span>)
        From.value.uri.secure = self.secure
        From.tag = self.localTag
        CSeq = Header(str(self.localSeq) + <span class="p_string">' '</span> + method, <span class="p_string">'CSeq'</span>)
        CallId = Header(self.callId, <span class="p_string">'Call-ID'</span>)
        MaxForwards = Header(str(self.maxForwards), <span class="p_string">'Max-Forwards'</span>)
        Via = self.stack.createVia(self.secure)
        Via.branch = Transaction.createBranch([To.value, From.value, CallId.value, CSeq.number], False)
        <span class="p_commentline"># Transport adds other parameters such as maddr, ttl </span>

        <span class="p_word">if</span> <span class="p_word">not</span> self.localTarget:
            self.localTarget = self.stack.uri.dup()
            self.localTarget.user = self.localParty.uri.user
        <span class="p_commentline"># put Contact is every request. app may remove or override it.</span>
        Contact = Header(str(self.localTarget), <span class="p_string">'Contact'</span>)
        Contact.value.uri.secure = self.secure
        
        headers = [To, From, CSeq, CallId, MaxForwards, Via, Contact]
        
        <span class="p_word">if</span> self.routeSet: 
            <span class="p_word">for</span> route <span class="p_word">in</span> map(<span class="p_word">lambda</span> x: Header(str(x), <span class="p_string">'Route'</span>), self.routeSet):
                route.value.uri.secure = self.secure
                <span class="p_commentline">#print 'adding route header', route</span>
                headers.append(route)
        <span class="p_commentline"># app adds other headers such as Supported, Require and Proxy-Require</span>
        <span class="p_word">if</span> contentType:
            headers.append(Header(contentType, <span class="p_string">'Content-Type'</span>))
        self.request = Message.createRequest(method, str(uri), headers, content)
        <span class="p_word">return</span> self.request


</PRE><DIV class="commentbox">From RFC3261 p.57<pre>10.2 Constructing the REGISTER Request

   REGISTER requests add, remove, and query bindings.  A REGISTER
   request can add a new binding between an address-of-record and one or
   more contact addresses.  Registration on behalf of a particular
   address-of-record can be performed by a suitably authorized third
   party.  A client can also remove previous bindings or query to
   determine which bindings are currently in place for an address-of-
   record.

   Except as noted, the construction of the REGISTER request and the
   behavior of clients sending a REGISTER request is identical to the
   general UAC behavior described in Section 8.1 and Section 17.1.

   A REGISTER request does not establish a dialog.  A UAC MAY include a
   Route header field in a REGISTER request based on a pre-existing
   route set as described in Section 8.1.  The Record-Route header field
   has no meaning in REGISTER requests or responses, and MUST be ignored
   if present.  In particular, the UAC MUST NOT create a new route set
   based on the presence or absence of a Record-Route header field in
   any response to a REGISTER request.

   The following header fields, except Contact, MUST be included in a
   REGISTER request.  A Contact header field MAY be included:

      Request-URI: The Request-URI names the domain of the location
           service for which the registration is meant (for example,
           "sip:chicago.com").  The "userinfo" and "@" components of the
           SIP URI MUST NOT be present.

      To: The To header field contains the address of record whose
           registration is to be created, queried, or modified.  The To
           header field and the Request-URI field typically differ, as
           the former contains a user name.  This address-of-record MUST
           be a SIP URI or SIPS URI.


      From: The From header field contains the address-of-record of the
           person responsible for the registration.  The value is the
           same as the To header field unless the request is a third-
           party registration.

      Call-ID: All registrations from a UAC SHOULD use the same Call-ID
           header field value for registrations sent to a particular
           registrar.

           If the same client were to use different Call-ID values, a
           registrar could not detect whether a delayed REGISTER request
           might have arrived out of order.

      CSeq: The CSeq value guarantees proper ordering of REGISTER
           requests.  A UA MUST increment the CSeq value by one for each
           REGISTER request with the same Call-ID.

      Contact: REGISTER requests MAY contain a Contact header field with
           zero or more values containing address bindings.

   UAs MUST NOT send a new registration (that is, containing new Contact
   header field values, as opposed to a retransmission) until they have
   received a final response from the registrar for the previous one or
   the previous REGISTER request has timed out.
























                                                 bob
                                               +----+
                                               | UA |
                                               |    |
                                               +----+
                                                  |
                                                  |3)INVITE
                                                  |   carol@chicago.com
         chicago.com        +--------+            V
         +---------+ 2)Store|Location|4)Query +-----+
         |Registrar|=======&amp;gt;| Service|&amp;lt;=======|Proxy|sip.chicago.com
         +---------+        +--------+=======&amp;gt;+-----+
               A                      5)Resp      |
               |                                  |
               |                                  |
     1)REGISTER|                                  |
               |                                  |
            +----+                                |
            | UA |&amp;lt;-------------------------------+
   cube2214a|    |                            6)INVITE
            +----+                    carol@cube2214a.chicago.com
             carol

                      Figure 2: REGISTER example

      The following Contact header parameters have a special meaning in
           REGISTER requests:

      action: The "action" parameter from RFC 2543 has been deprecated.
           UACs SHOULD NOT use the "action" parameter.

      expires: The "expires" parameter indicates how long the UA would
           like the binding to be valid.  The value is a number
           indicating seconds.  If this parameter is not provided, the
           value of the Expires header field is used instead.
           Implementations MAY treat values larger than 2**32-1
           (4294967295 seconds or 136 years) as equivalent to 2**32-1.
           Malformed values SHOULD be treated as equivalent to 3600.</pre></DIV><PRE>
    <span class="p_word">def</span> createRegister(self, aor):
        <span class="p_triple">'''Create a REGISTER request for given aor (Address).'''</span>
        <span class="p_word">if</span> aor: self.remoteParty = Address(str(aor))
        <span class="p_word">if</span> <span class="p_word">not</span> self.localParty: self.localParty = Address(str(self.remoteParty))
        <span class="p_word">return</span> self.createRequest(<span class="p_string">'REGISTER'</span>)
    

</PRE><DIV class="commentbox">From RFC3261 p.41<pre>8.1.2 Sending the Request

   The destination for the request is then computed.  Unless there is
   local policy specifying otherwise, the destination MUST be determined
   by applying the DNS procedures described in [4] as follows.  If the
   first element in the route set indicated a strict router (resulting
   in forming the request as described in Section 12.2.1.1), the
   procedures MUST be applied to the Request-URI of the request.
   Otherwise, the procedures are applied to the first Route header field
   value in the request (if one exists), or to the request's Request-URI
   if there is no Route header field present.  These procedures yield an
   ordered set of address, port, and transports to attempt.  Independent
   of which URI is used as input to the procedures of [4], if the
   Request-URI specifies a SIPS resource, the UAC MUST follow the
   procedures of [4] as if the input URI were a SIPS URI.

   Local policy MAY specify an alternate set of destinations to attempt.
   If the Request-URI contains a SIPS URI, any alternate destinations
   MUST be contacted with TLS.  Beyond that, there are no restrictions
   on the alternate destinations if the request contains no Route header
   field.  This provides a simple alternative to a pre-existing route
   set as a way to specify an outbound proxy.  However, that approach
   for configuring an outbound proxy is NOT RECOMMENDED; a pre-existing
   route set with a single URI SHOULD be used instead.  If the request
   contains a Route header field, the request SHOULD be sent to the
   locations derived from its topmost value, but MAY be sent to any
   server that the UA is certain will honor the Route and Request-URI
   policies specified in this document (as opposed to those in RFC
   2543).  In particular, a UAC configured with an outbound proxy SHOULD
   attempt to send the request to the location indicated in the first
   Route header field value instead of adopting the policy of sending
   all messages to the outbound proxy.

      This ensures that outbound proxies that do not add Record-Route
      header field values will drop out of the path of subsequent
      requests.  It allows endpoints that cannot resolve the first Route
      URI to delegate that task to an outbound proxy.

   The UAC SHOULD follow the procedures defined in [4] for stateful
   elements, trying each address until a server is contacted.  Each try
   constitutes a new transaction, and therefore each carries a different
   topmost Via header field value with a new branch parameter.
   Furthermore, the transport value in the Via header field is set to
   whatever transport was determined for the target server.</pre></DIV><PRE>
    <span class="p_word">def</span> sendRequest(self, request):
        <span class="p_triple">'''Send a UAC request Message.'''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.request <span class="p_word">and</span> request.method == <span class="p_string">'REGISTER'</span>: 
            <span class="p_word">if</span> <span class="p_word">not</span> self.transaction <span class="p_word">and</span> self.transaction.state != <span class="p_string">'completed'</span> <span class="p_word">and</span> self.transaction.state != <span class="p_string">'terminated'</span>: 
                <span class="p_word">raise</span> ValueError, <span class="p_string">'Cannot re-REGISTER since pending registration'</span>
        
        self.request = request <span class="p_commentline"># store for future</span>
        
        <span class="p_word">if</span> <span class="p_word">not</span> request.Route: self.remoteTarget = request.uri
        target = self.remoteTarget
        
        <span class="p_word">if</span> request.Route:
            routes = request.all(<span class="p_string">'Route'</span>)
            <span class="p_word">if</span> len(routes) &gt; <span class="p_number">0</span>:
                target = routes[<span class="p_number">0</span>].value.uri
                <span class="p_word">if</span> <span class="p_word">not</span> target <span class="p_word">or</span> <span class="p_string">'lr'</span> <span class="p_word">not</span> <span class="p_word">in</span> target.param: <span class="p_commentline"># strict route</span>
                    <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'strict route target='</span>, target, <span class="p_string">'routes='</span>, routes
                    <span class="p_word">del</span> routes[<span class="p_number">0</span>] <span class="p_commentline"># ignore first route</span>
                    <span class="p_word">if</span> len(routes) &gt; <span class="p_number">0</span>:
                        <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'appending our route'</span>
                        routes.append(Header(str(request.uri), <span class="p_string">'Route'</span>))
                    request.Route = routes
                    request.uri = target;
        
        <span class="p_commentline"># TODO: remove any Route header in REGISTER request</span>
        
        self.stack.sending(self, request) 
        
        <span class="p_commentline"># TODO: replace the following with <a href="http://www.rfc-editor.org/rfc/rfc3263.txt">RFC3263</a> to return multiple candidates. Add TCP and UDP and is possible TLS.</span>
        dest = target.dup()
        dest.port = target.port <span class="p_word">or</span> target.secure <span class="p_word">and</span> <span class="p_number">5061</span> <span class="p_word">or</span> <span class="p_number">5060</span>
        <span class="p_word">if</span> <span class="p_word">not</span> isIPv4(dest.host):
            <span class="p_word">try</span>: dest.host = gethostbyname(dest.host)
            <span class="p_word">except</span>: <span class="p_word">pass</span>
        <span class="p_word">if</span> isIPv4(dest.host):
            self.remoteCandidates = [dest]
        
        <span class="p_commentline"># continue processing as if we received multiple candidates</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.remoteCandidates <span class="p_word">or</span> len(self.remoteCandidates) == <span class="p_number">0</span>:
            self.error(<span class="p_word">None</span>, <span class="p_string">'cannot resolve DNS target'</span>)
            <span class="p_word">return</span>
        target = self.remoteCandidates.pop(<span class="p_number">0</span>)
        <span class="p_word">if</span> self.request.method != <span class="p_string">'ACK'</span>:
            <span class="p_commentline"># start a client transaction to send the request</span>
            self.transaction = Transaction.createClient(self.stack, self, self.request, self.stack.transport, target.hostPort)
        <span class="p_word">else</span>: <span class="p_commentline"># directly send ACK on transport layer</span>
            self.stack.send(self.request, target.hostPort)

    <span class="p_word">def</span> retryNextCandidate(self):
        <span class="p_triple">'''Retry next DNS resolved address.'''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.remoteCandidates <span class="p_word">or</span> len(self.remoteCandidates) == <span class="p_number">0</span>:
            <span class="p_word">raise</span> ValueError, <span class="p_string">'No more DNS resolved address to try'</span>
        target = URI(self.remoteCandiates.pop(<span class="p_number">0</span>))
        self.request.first(<span class="p_string">'Via'</span>).branch += <span class="p_string">'A'</span> <span class="p_commentline"># so that we create a different new transaction</span>
        transaction = Transaction.createClient(self.stack, self, self.request, self.stack.transport, target.hostPort)
    
    @staticmethod
    <span class="p_word">def</span> canCreateDialog(request, response):
        <span class="p_triple">'''Whether we can create a dialog for this response of this request?
        Default is to create dialog for 2xx response to INVITE or SUBSCRIBE.'''</span>
        <span class="p_word">return</span> response.is2xx <span class="p_word">and</span> (request.method == <span class="p_string">'INVITE'</span> <span class="p_word">or</span> request.method == <span class="p_string">'SUBSCRIBE'</span>)
     

</PRE><DIV class="commentbox">From RFC3261 p.42<pre>8.1.3 Processing Responses

   Responses are first processed by the transport layer and then passed
   up to the transaction layer.  The transaction layer performs its
   processing and then passes the response up to the TU.  The majority
   of response processing in the TU is method specific.  However, there
   are some general behaviors independent of the method.

8.1.3.1 Transaction Layer Errors

   In some cases, the response returned by the transaction layer will
   not be a SIP message, but rather a transaction layer error.  When a
   timeout error is received from the transaction layer, it MUST be
   treated as if a 408 (Request Timeout) status code has been received.
   If a fatal transport error is reported by the transport layer
   (generally, due to fatal ICMP errors in UDP or connection failures in
   TCP), the condition MUST be treated as a 503 (Service Unavailable)
   status code.

8.1.3.2 Unrecognized Responses

   A UAC MUST treat any final response it does not recognize as being
   equivalent to the x00 response code of that class, and MUST be able
   to process the x00 response code for all classes.  For example, if a
   UAC receives an unrecognized response code of 431, it can safely
   assume that there was something wrong with its request and treat the
   response as if it had received a 400 (Bad Request) response code.  A
   UAC MUST treat any provisional response different than 100 that it
   does not recognize as 183 (Session Progress).  A UAC MUST be able to
   process 100 and 183 responses.


8.1.3.3 Vias

   If more than one Via header field value is present in a response, the
   UAC SHOULD discard the message.

      The presence of additional Via header field values that precede
      the originator of the request suggests that the message was
      misrouted or possibly corrupted.

8.1.3.4 Processing 3xx Responses

   Upon receipt of a redirection response (for example, a 301 response
   status code), clients SHOULD use the URI(s) in the Contact header
   field to formulate one or more new requests based on the redirected
   request.  This process is similar to that of a proxy recursing on a
   3xx class response as detailed in Sections 16.5 and 16.6.  A client
   starts with an initial target set containing exactly one URI, the
   Request-URI of the original request.  If a client wishes to formulate
   new requests based on a 3xx class response to that request, it places
   the URIs to try into the target set.  Subject to the restrictions in
   this specification, a client can choose which Contact URIs it places
   into the target set.  As with proxy recursion, a client processing
   3xx class responses MUST NOT add any given URI to the target set more
   than once.  If the original request had a SIPS URI in the Request-
   URI, the client MAY choose to recurse to a non-SIPS URI, but SHOULD
   inform the user of the redirection to an insecure URI.

      Any new request may receive 3xx responses themselves containing
      the original URI as a contact.  Two locations can be configured to
      redirect to each other.  Placing any given URI in the target set
      only once prevents infinite redirection loops.

   As the target set grows, the client MAY generate new requests to the
   URIs in any order.  A common mechanism is to order the set by the "q"
   parameter value from the Contact header field value.  Requests to the
   URIs MAY be generated serially or in parallel.  One approach is to
   process groups of decreasing q-values serially and process the URIs
   in each q-value group in parallel.  Another is to perform only serial
   processing in decreasing q-value order, arbitrarily choosing between
   contacts of equal q-value.

   If contacting an address in the list results in a failure, as defined
   in the next paragraph, the element moves to the next address in the
   list, until the list is exhausted.  If the list is exhausted, then
   the request has failed.



   Failures SHOULD be detected through failure response codes (codes
   greater than 399); for network errors the client transaction will
   report any transport layer failures to the transaction user.  Note
   that some response codes (detailed in 8.1.3.5) indicate that the
   request can be retried; requests that are reattempted should not be
   considered failures.

   When a failure for a particular contact address is received, the
   client SHOULD try the next contact address.  This will involve
   creating a new client transaction to deliver a new request.

   In order to create a request based on a contact address in a 3xx
   response, a UAC MUST copy the entire URI from the target set into the
   Request-URI, except for the "method-param" and "header" URI
   parameters (see Section 19.1.1 for a definition of these parameters).
   It uses the "header" parameters to create header field values for the
   new request, overwriting header field values associated with the
   redirected request in accordance with the guidelines in Section
   19.1.5.

   Note that in some instances, header fields that have been
   communicated in the contact address may instead append to existing
   request header fields in the original redirected request.  As a
   general rule, if the header field can accept a comma-separated list
   of values, then the new header field value MAY be appended to any
   existing values in the original redirected request.  If the header
   field does not accept multiple values, the value in the original
   redirected request MAY be overwritten by the header field value
   communicated in the contact address.  For example, if a contact
   address is returned with the following value:

      sip:user@host?Subject=foo&amp;Call-Info=&amp;lt;http://www.foo.com&amp;gt;

   Then any Subject header field in the original redirected request is
   overwritten, but the HTTP URL is merely appended to any existing
   Call-Info header field values.

   It is RECOMMENDED that the UAC reuse the same To, From, and Call-ID
   used in the original redirected request, but the UAC MAY also choose
   to update the Call-ID header field value for new requests, for
   example.

   Finally, once the new request has been constructed, it is sent using
   a new client transaction, and therefore MUST have a new branch ID in
   the top Via field as discussed in Section 8.1.1.7.



   In all other respects, requests sent upon receipt of a redirect
   response SHOULD re-use the header fields and bodies of the original
   request.

   In some instances, Contact header field values may be cached at UAC
   temporarily or permanently depending on the status code received and
   the presence of an expiration interval; see Sections 21.3.2 and
   21.3.3.

8.1.3.5 Processing 4xx Responses

   Certain 4xx response codes require specific UA processing,
   independent of the method.

   If a 401 (Unauthorized) or 407 (Proxy Authentication Required)
   response is received, the UAC SHOULD follow the authorization
   procedures of Section 22.2 and Section 22.3 to retry the request with
   credentials.

   If a 413 (Request Entity Too Large) response is received (Section
   21.4.11), the request contained a body that was longer than the UAS
   was willing to accept.  If possible, the UAC SHOULD retry the
   request, either omitting the body or using one of a smaller length.

   If a 415 (Unsupported Media Type) response is received (Section
   21.4.13), the request contained media types not supported by the UAS.
   The UAC SHOULD retry sending the request, this time only using
   content with types listed in the Accept header field in the response,
   with encodings listed in the Accept-Encoding header field in the
   response, and with languages listed in the Accept-Language in the
   response.

   If a 416 (Unsupported URI Scheme) response is received (Section
   21.4.14), the Request-URI used a URI scheme not supported by the
   server.  The client SHOULD retry the request, this time, using a SIP
   URI.

   If a 420 (Bad Extension) response is received (Section 21.4.15), the
   request contained a Require or Proxy-Require header field listing an
   option-tag for a feature not supported by a proxy or UAS.  The UAC
   SHOULD retry the request, this time omitting any extensions listed in
   the Unsupported header field in the response.

   In all of the above cases, the request is retried by creating a new
   request with the appropriate modifications.  This new request
   constitutes a new transaction and SHOULD have the same value of the
   Call-ID, To, and From of the previous request, but the CSeq should
   contain a new sequence number that is one higher than the previous.
   With other 4xx responses, including those yet to be defined, a retry
   may or may not be possible depending on the method and the use case.</pre></DIV><PRE>
    <span class="p_word">def</span> receivedResponse(self, transaction, response):
        <span class="p_triple">'''Received a new response from the transaction.'''</span>
        <span class="p_word">if</span> transaction <span class="p_word">and</span> transaction != self.transaction:
            <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'Invalid transaction received %r!=%r'</span>%(transaction, self.transaction)
            <span class="p_word">return</span>
        <span class="p_word">if</span> len(response.all(<span class="p_string">'Via'</span>)) &gt; <span class="p_number">1</span>:
            <span class="p_word">raise</span> ValueError, <span class="p_string">'More than one Via header in response'</span>
        <span class="p_word">if</span> response.is1xx:
            <span class="p_word">if</span> self.cancelRequest:
                cancel = Transaction.createClient(self.stack, self, self.cancelRequest, transaction.transport, transaction.remote)
                self.cancelRequest = <span class="p_word">None</span>
            <span class="p_word">else</span>:
                self.stack.receivedResponse(self, response)
        <span class="p_word">elif</span> response.response == <span class="p_number">401</span> <span class="p_word">or</span> response.response == <span class="p_number">407</span>: <span class="p_commentline"># authentication challenge</span>
            <span class="p_word">if</span> <span class="p_word">not</span> self.authenticate(response, self.transaction): <span class="p_commentline"># couldn't authenticate</span>
                self.stack.receivedResponse(self, response)
        <span class="p_word">else</span>:
            <span class="p_word">if</span> self.canCreateDialog(self.request, response):
                dialog = Dialog.createClient(self.stack, self.request, response, transaction)
                self.stack.dialogCreated(dialog, self)
                self.stack.receivedResponse(dialog, response)
                <span class="p_word">if</span> self.autoack <span class="p_word">and</span> self.request.method == <span class="p_string">'INVITE'</span>: 
                    dialog.sendRequest(dialog.createRequest(<span class="p_string">'ACK'</span>))
            <span class="p_word">else</span>:
                self.stack.receivedResponse(self, response)


</PRE><DIV class="commentbox">From RFC3261 p.46<pre>8.2 UAS Behavior

   When a request outside of a dialog is processed by a UAS, there is a
   set of processing rules that are followed, independent of the method.
   Section 12 gives guidance on how a UAS can tell whether a request is
   inside or outside of a dialog.

   Note that request processing is atomic.  If a request is accepted,
   all state changes associated with it MUST be performed.  If it is
   rejected, all state changes MUST NOT be performed.

   UASs SHOULD process the requests in the order of the steps that
   follow in this section (that is, starting with authentication, then
   inspecting the method, the header fields, and so on throughout the
   remainder of this section).

8.2.1 Method Inspection

   Once a request is authenticated (or authentication is skipped), the
   UAS MUST inspect the method of the request.  If the UAS recognizes
   but does not support the method of a request, it MUST generate a 405
   (Method Not Allowed) response.  Procedures for generating responses
   are described in Section 8.2.6.  The UAS MUST also add an Allow
   header field to the 405 (Method Not Allowed) response.  The Allow
   header field MUST list the set of methods supported by the UAS
   generating the message.  The Allow header field is presented in
   Section 20.5.

   If the method is one supported by the server, processing continues.

8.2.2 Header Inspection

   If a UAS does not understand a header field in a request (that is,
   the header field is not defined in this specification or in any
   supported extension), the server MUST ignore that header field and
   continue processing the message.  A UAS SHOULD ignore any malformed
   header fields that are not necessary for processing requests.

8.2.2.1 To and Request-URI

   The To header field identifies the original recipient of the request
   designated by the user identified in the From field.  The original
   recipient may or may not be the UAS processing the request, due to
   call forwarding or other proxy operations.  A UAS MAY apply any
   policy it wishes to determine whether to accept requests when the To
   header field is not the identity of the UAS.  However, it is
   RECOMMENDED that a UAS accept requests even if they do not recognize
   the URI scheme (for example, a tel: URI) in the To header field, or
   if the To header field does not address a known or current user of
   this UAS.  If, on the other hand, the UAS decides to reject the
   request, it SHOULD generate a response with a 403 (Forbidden) status
   code and pass it to the server transaction for transmission.

   However, the Request-URI identifies the UAS that is to process the
   request.  If the Request-URI uses a scheme not supported by the UAS,
   it SHOULD reject the request with a 416 (Unsupported URI Scheme)
   response.  If the Request-URI does not identify an address that the
   UAS is willing to accept requests for, it SHOULD reject the request
   with a 404 (Not Found) response.  Typically, a UA that uses the
   REGISTER method to bind its address-of-record to a specific contact
   address will see requests whose Request-URI equals that contact
   address.  Other potential sources of received Request-URIs include
   the Contact header fields of requests and responses sent by the UA
   that establish or refresh dialogs.

8.2.2.2 Merged Requests

   If the request has no tag in the To header field, the UAS core MUST
   check the request against ongoing transactions.  If the From tag,
   Call-ID, and CSeq exactly match those associated with an ongoing
   transaction, but the request does not match that transaction (based
   on the matching rules in Section 17.2.3), the UAS core SHOULD
   generate a 482 (Loop Detected) response and pass it to the server
   transaction.

      The same request has arrived at the UAS more than once, following
      different paths, most likely due to forking.  The UAS processes
      the first such request received and responds with a 482 (Loop
      Detected) to the rest of them.

8.2.2.3 Require

   Assuming the UAS decides that it is the proper element to process the
   request, it examines the Require header field, if present.

   The Require header field is used by a UAC to tell a UAS about SIP
   extensions that the UAC expects the UAS to support in order to
   process the request properly.  Its format is described in Section
   20.32.  If a UAS does not understand an option-tag listed in a
   Require header field, it MUST respond by generating a response with
   status code 420 (Bad Extension).  The UAS MUST add an Unsupported
   header field, and list in it those options it does not understand
   amongst those in the Require header field of the request.
   Note that Require and Proxy-Require MUST NOT be used in a SIP CANCEL
   request, or in an ACK request sent for a non-2xx response.  These
   header fields MUST be ignored if they are present in these requests.

   An ACK request for a 2xx response MUST contain only those Require and
   Proxy-Require values that were present in the initial request.

   Example:

      UAC-&amp;gt;UAS:   INVITE sip:watson@bell-telephone.com SIP/2.0
                  Require: 100rel

      UAS-&amp;gt;UAC:   SIP/2.0 420 Bad Extension
                  Unsupported: 100rel

      This behavior ensures that the client-server interaction will
      proceed without delay when all options are understood by both
      sides, and only slow down if options are not understood (as in the
      example above).  For a well-matched client-server pair, the
      interaction proceeds quickly, saving a round-trip often required
      by negotiation mechanisms.  In addition, it also removes ambiguity
      when the client requires features that the server does not
      understand.  Some features, such as call handling fields, are only
      of interest to end systems.

8.2.3 Content Processing

   Assuming the UAS understands any extensions required by the client,
   the UAS examines the body of the message, and the header fields that
   describe it.  If there are any bodies whose type (indicated by the
   Content-Type), language (indicated by the Content-Language) or
   encoding (indicated by the Content-Encoding) are not understood, and
   that body part is not optional (as indicated by the Content-
   Disposition header field), the UAS MUST reject the request with a 415
   (Unsupported Media Type) response.  The response MUST contain an
   Accept header field listing the types of all bodies it understands,
   in the event the request contained bodies of types not supported by
   the UAS.  If the request contained content encodings not understood
   by the UAS, the response MUST contain an Accept-Encoding header field
   listing the encodings understood by the UAS.  If the request
   contained content with languages not understood by the UAS, the
   response MUST contain an Accept-Language header field indicating the
   languages understood by the UAS.  Beyond these checks, body handling
   depends on the method and type.  For further information on the
   processing of content-specific header fields, see Section 7.4 as well
   as Section 20.11 through 20.15.


8.2.4 Applying Extensions

   A UAS that wishes to apply some extension when generating the
   response MUST NOT do so unless support for that extension is
   indicated in the Supported header field in the request.  If the
   desired extension is not supported, the server SHOULD rely only on
   baseline SIP and any other extensions supported by the client.  In
   rare circumstances, where the server cannot process the request
   without the extension, the server MAY send a 421 (Extension Required)
   response.  This response indicates that the proper response cannot be
   generated without support of a specific extension.  The needed
   extension(s) MUST be included in a Require header field in the
   response.  This behavior is NOT RECOMMENDED, as it will generally
   break interoperability.

   Any extensions applied to a non-421 response MUST be listed in a
   Require header field included in the response.  Of course, the server
   MUST NOT apply extensions not listed in the Supported header field in
   the request.  As a result of this, the Require header field in a
   response will only ever contain option tags defined in standards-
   track RFCs.

8.2.5 Processing the Request

   Assuming all of the checks in the previous subsections are passed,
   the UAS processing becomes method-specific.  Section 10 covers the
   REGISTER request, Section 11 covers the OPTIONS request, Section 13
   covers the INVITE request, and Section 15 covers the BYE request.</pre></DIV><PRE>
    <span class="p_word">def</span> receivedRequest(self, transaction, request):
        <span class="p_triple">'''New incoming request in this transaction.'''</span>
        <span class="p_word">if</span> transaction <span class="p_word">and</span> self.transaction <span class="p_word">and</span> transaction != self.transaction <span class="p_word">and</span> request.method != <span class="p_string">'CANCEL'</span>:
            <span class="p_word">raise</span> ValueError, <span class="p_string">'Invalid transaction for received request'</span>
        self.server = True <span class="p_commentline"># this becomes a UAS</span>
        <span class="p_commentline">#if request.method == 'REGISTER':</span>
        <span class="p_commentline">#    response = transaction.createResponse(405, 'Method not allowed')</span>
        <span class="p_commentline">#    response.Allow = Header('INVITE, ACK, CANCEL, BYE', 'Allow') # TODO make this configurable</span>
        <span class="p_commentline">#    transaction.sendResponse(response)</span>
        <span class="p_commentline">#    return</span>
        <span class="p_word">if</span> request.uri.scheme <span class="p_word">not</span> <span class="p_word">in</span> [<span class="p_string">'sip'</span>, <span class="p_string">'sips'</span>]:
            transaction.sendResponse(transaction.createResponse(<span class="p_number">416</span>, <span class="p_string">'Unsupported URI scheme'</span>))
            <span class="p_word">return</span>
        <span class="p_word">if</span> <span class="p_string">'tag'</span> <span class="p_word">not</span> <span class="p_word">in</span> request.To: <span class="p_commentline"># out of dialog request</span>
            <span class="p_word">if</span> self.stack.findOtherTransaction(request, transaction): <span class="p_commentline"># request merging?</span>
                transaction.sendResponse(transaction.createResponse(<span class="p_number">482</span>, <span class="p_string">"Loop detected - found another transaction"</span>))
                <span class="p_word">return</span>
        <span class="p_word">if</span> request.Require: <span class="p_commentline"># TODO let the application handle Require header</span>
            <span class="p_word">if</span> request.method != <span class="p_string">'CANCEL'</span> <span class="p_word">and</span> request.method != <span class="p_string">'ACK'</span>: 
                response = transaction.createResponse(<span class="p_number">420</span>, <span class="p_string">'Bad extension'</span>)
                response.Unsupported = Header(str(request.Require.value), <span class="p_string">'Unsupported'</span>)
                transaction.sendResponse(response)
                <span class="p_word">return</span>
        <span class="p_word">if</span> transaction: self.transaction = transaction <span class="p_commentline"># store it</span>
        
        <span class="p_word">if</span> request.method == <span class="p_string">'CANCEL'</span>: 
            original = self.stack.findTransaction(Transaction.createId(transaction.branch, <span class="p_string">'INVITE'</span>))
            <span class="p_word">if</span> <span class="p_word">not</span> original:
                transaction.sendResponse(transaction.createResponse(<span class="p_number">481</span>, <span class="p_string">'Original transaction not found'</span>))
                <span class="p_word">return</span>
            <span class="p_word">if</span> original.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> original.state == <span class="p_string">'trying'</span>:
                original.sendResponse(original.createResponse(<span class="p_number">487</span>, <span class="p_string">'Request terminated'</span>))
            transaction.sendResponse(transaction.createResponse(<span class="p_number">200</span>, <span class="p_string">'OK'</span>)) <span class="p_commentline"># CANCEL response</span>
            <span class="p_commentline"># TODO: the To tag must be same in the two responses</span>
            
        self.stack.receivedRequest(self, request)


</PRE><DIV class="commentbox">From RFC3261 p.49<pre>8.2.6 Generating the Response

   When a UAS wishes to construct a response to a request, it follows
   the general procedures detailed in the following subsections.
   Additional behaviors specific to the response code in question, which
   are not detailed in this section, may also be required.

   Once all procedures associated with the creation of a response have
   been completed, the UAS hands the response back to the server
   transaction from which it received the request.

8.2.6.1 Sending a Provisional Response

   One largely non-method-specific guideline for the generation of
   responses is that UASs SHOULD NOT issue a provisional response for a
   non-INVITE request.  Rather, UASs SHOULD generate a final response to
   a non-INVITE request as soon as possible.


   When a 100 (Trying) response is generated, any Timestamp header field
   present in the request MUST be copied into this 100 (Trying)
   response.  If there is a delay in generating the response, the UAS
   SHOULD add a delay value into the Timestamp value in the response.
   This value MUST contain the difference between the time of sending of
   the response and receipt of the request, measured in seconds.

8.2.6.2 Headers and Tags

   The From field of the response MUST equal the From header field of
   the request.  The Call-ID header field of the response MUST equal the
   Call-ID header field of the request.  The CSeq header field of the
   response MUST equal the CSeq field of the request.  The Via header
   field values in the response MUST equal the Via header field values
   in the request and MUST maintain the same ordering.

   If a request contained a To tag in the request, the To header field
   in the response MUST equal that of the request.  However, if the To
   header field in the request did not contain a tag, the URI in the To
   header field in the response MUST equal the URI in the To header
   field; additionally, the UAS MUST add a tag to the To header field in
   the response (with the exception of the 100 (Trying) response, in
   which a tag MAY be present).  This serves to identify the UAS that is
   responding, possibly resulting in a component of a dialog ID.  The
   same tag MUST be used for all responses to that request, both final
   and provisional (again excepting the 100 (Trying)).  Procedures for
   the generation of tags are defined in Section 19.3.</pre></DIV><PRE>
    <span class="p_word">def</span> sendResponse(self, response, responsetext=<span class="p_word">None</span>, content=<span class="p_word">None</span>, contentType=<span class="p_word">None</span>, createDialog=True):
        <span class="p_word">if</span> <span class="p_word">not</span> self.request: 
            <span class="p_word">raise</span> ValueError, <span class="p_string">'Invalid request in sending a response'</span>
        <span class="p_word">if</span> isinstance(response, int): 
            response = self.createResponse(response, responsetext, content, contentType)
        <span class="p_word">if</span> createDialog <span class="p_word">and</span> self.canCreateDialog(self.request, response):
            <span class="p_word">if</span> self.request[<span class="p_string">'Record-Route'</span>]: response[<span class="p_string">'Record-Route'</span>] = self.request[<span class="p_string">'Record-Route'</span>]
            <span class="p_word">if</span> <span class="p_word">not</span> response.Contact: 
                contact = Address(str(self.contact))
                <span class="p_word">if</span> <span class="p_word">not</span> contact.uri.user: contact.uri.user = self.request.To.value.uri.user
                contact.uri.secure = self.secure
                response.Contact = Header(str(contact), <span class="p_string">'Contact'</span>)
            dialog = Dialog.createServer(self.stack, self.request, response, self.transaction)
            self.stack.dialogCreated(dialog, self)
            self.stack.sending(dialog, response)
        <span class="p_word">else</span>:
            self.stack.sending(self, response)
            
        <span class="p_word">if</span> <span class="p_word">not</span> self.transaction: <span class="p_commentline"># send on transport</span>
            self.stack.send(response, response.first(<span class="p_string">'Via'</span>).viaUri.hostPort)
        <span class="p_word">else</span>:
            self.transaction.sendResponse(response)
    
    <span class="p_word">def</span> createResponse(self, response, responsetext, content=<span class="p_word">None</span>, contentType=<span class="p_word">None</span>):
        <span class="p_word">if</span> <span class="p_word">not</span> self.request:
            <span class="p_word">raise</span> ValueError, <span class="p_string">'Invalid request in creating a response'</span>
        response = Message.createResponse(response, responsetext, <span class="p_word">None</span>, content, self.request)
        <span class="p_word">if</span> contentType: response[<span class="p_string">'Content-Type'</span>] = Header(contentType, <span class="p_string">'Content-Type'</span>)
        <span class="p_word">if</span> response.response != <span class="p_number">100</span> <span class="p_word">and</span> <span class="p_string">'tag'</span> <span class="p_word">not</span> <span class="p_word">in</span> response.To: response.To[<span class="p_string">'tag'</span>] = self.localTag
        <span class="p_word">return</span> response;
    

</PRE><DIV class="commentbox">From RFC3261 p.53<pre>9 Canceling a Request

   The previous section has discussed general UA behavior for generating
   requests and processing responses for requests of all methods.  In
   this section, we discuss a general purpose method, called CANCEL.

   The CANCEL request, as the name implies, is used to cancel a previous
   request sent by a client.  Specifically, it asks the UAS to cease
   processing the request and to generate an error response to that
   request.  CANCEL has no effect on a request to which a UAS has
   already given a final response.  Because of this, it is most useful
   to CANCEL requests to which it can take a server long time to
   respond.  For this reason, CANCEL is best for INVITE requests, which
   can take a long time to generate a response.  In that usage, a UAS
   that receives a CANCEL request for an INVITE, but has not yet sent a
   final response, would "stop ringing", and then respond to the INVITE
   with a specific error response (a 487).

   CANCEL requests can be constructed and sent by both proxies and user
   agent clients.  Section 15 discusses under what conditions a UAC
   would CANCEL an INVITE request, and Section 16.10 discusses proxy
   usage of CANCEL.

   A stateful proxy responds to a CANCEL, rather than simply forwarding
   a response it would receive from a downstream element.  For that
   reason, CANCEL is referred to as a "hop-by-hop" request, since it is
   responded to at each stateful proxy hop.

9.1 Client Behavior

   A CANCEL request SHOULD NOT be sent to cancel a request other than
   INVITE.

      Since requests other than INVITE are responded to immediately,
      sending a CANCEL for a non-INVITE request would always create a
      race condition.


   The following procedures are used to construct a CANCEL request.  The
   Request-URI, Call-ID, To, the numeric part of CSeq, and From header
   fields in the CANCEL request MUST be identical to those in the
   request being cancelled, including tags.  A CANCEL constructed by a
   client MUST have only a single Via header field value matching the
   top Via value in the request being cancelled.  Using the same values
   for these header fields allows the CANCEL to be matched with the
   request it cancels (Section 9.2 indicates how such matching occurs).
   However, the method part of the CSeq header field MUST have a value
   of CANCEL.  This allows it to be identified and processed as a
   transaction in its own right (See Section 17).

   If the request being cancelled contains a Route header field, the
   CANCEL request MUST include that Route header field's values.

      This is needed so that stateless proxies are able to route CANCEL
      requests properly.

   The CANCEL request MUST NOT contain any Require or Proxy-Require
   header fields.

   Once the CANCEL is constructed, the client SHOULD check whether it
   has received any response (provisional or final) for the request
   being cancelled (herein referred to as the "original request").

   If no provisional response has been received, the CANCEL request MUST
   NOT be sent; rather, the client MUST wait for the arrival of a
   provisional response before sending the request.  If the original
   request has generated a final response, the CANCEL SHOULD NOT be
   sent, as it is an effective no-op, since CANCEL has no effect on
   requests that have already generated a final response.  When the
   client decides to send the CANCEL, it creates a client transaction
   for the CANCEL and passes it the CANCEL request along with the
   destination address, port, and transport.  The destination address,
   port, and transport for the CANCEL MUST be identical to those used to
   send the original request.

      If it was allowed to send the CANCEL before receiving a response
      for the previous request, the server could receive the CANCEL
      before the original request.

   Note that both the transaction corresponding to the original request
   and the CANCEL transaction will complete independently.  However, a
   UAC canceling a request cannot rely on receiving a 487 (Request
   Terminated) response for the original request, as an RFC 2543-
   compliant UAS will not generate such a response.  If there is no
   final response for the original request in 64*T1 seconds (T1 is

   defined in Section 17.1.1.1), the client SHOULD then consider the
   original transaction cancelled and SHOULD destroy the client
   transaction handling the original request.

9.2 Server Behavior

   The CANCEL method requests that the TU at the server side cancel a
   pending transaction.  The TU determines the transaction to be
   cancelled by taking the CANCEL request, and then assuming that the
   request method is anything but CANCEL or ACK and applying the
   transaction matching procedures of Section 17.2.3.  The matching
   transaction is the one to be cancelled.

   The processing of a CANCEL request at a server depends on the type of
   server.  A stateless proxy will forward it, a stateful proxy might
   respond to it and generate some CANCEL requests of its own, and a UAS
   will respond to it.  See Section 16.10 for proxy treatment of CANCEL.

   A UAS first processes the CANCEL request according to the general UAS
   processing described in Section 8.2.  However, since CANCEL requests
   are hop-by-hop and cannot be resubmitted, they cannot be challenged
   by the server in order to get proper credentials in an Authorization
   header field.  Note also that CANCEL requests do not contain a
   Require header field.

   If the UAS did not find a matching transaction for the CANCEL
   according to the procedure above, it SHOULD respond to the CANCEL
   with a 481 (Call Leg/Transaction Does Not Exist).  If the transaction
   for the original request still exists, the behavior of the UAS on
   receiving a CANCEL request depends on whether it has already sent a
   final response for the original request.  If it has, the CANCEL
   request has no effect on the processing of the original request, no
   effect on any session state, and no effect on the responses generated
   for the original request.  If the UAS has not issued a final response
   for the original request, its behavior depends on the method of the
   original request.  If the original request was an INVITE, the UAS
   SHOULD immediately respond to the INVITE with a 487 (Request
   Terminated).  A CANCEL request has no impact on the processing of
   transactions with any other method defined in this specification.

   Regardless of the method of the original request, as long as the
   CANCEL matched an existing transaction, the UAS answers the CANCEL
   request itself with a 200 (OK) response.  This response is
   constructed following the procedures described in Section 8.2.6
   noting that the To tag of the response to the CANCEL and the To tag
   in the response to the original request SHOULD be the same.  The
   response to CANCEL is passed to the server transaction for
   transmission.</pre></DIV><PRE>
    <span class="p_word">def</span> sendCancel(self):
        <span class="p_triple">'''Cancel a request.'''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.transaction: 
            <span class="p_word">raise</span> ValueError, <span class="p_string">'No transaction for sending CANCEL'</span>

        self.cancelRequest = self.transaction.createCancel()
        <span class="p_word">if</span> self.transaction.state != <span class="p_string">'trying'</span> <span class="p_word">and</span> self.transaction.state != <span class="p_string">'calling'</span>:
            <span class="p_word">if</span> self.transaction.state == <span class="p_string">'proceeding'</span>:
                transaction = Transaction.createClient(self.stack, self, self.cancelRequest, self.transaction.transport, self.transaction.remote) 
            self.cancelRequest = <span class="p_word">None</span>
        <span class="p_commentline"># else don't send until 1xx is received </span>

    <span class="p_word">def</span> timeout(self, transaction):
        <span class="p_triple">'''A client transaction was timedout.'''</span>
        <span class="p_word">if</span> transaction <span class="p_word">and</span> transaction != self.transaction: <span class="p_commentline"># invalid transaction</span>
            <span class="p_word">return</span>
        self.transaction = <span class="p_word">None</span> 
        <span class="p_word">if</span> <span class="p_word">not</span> self.server: <span class="p_commentline"># UAC</span>
            <span class="p_word">if</span> self.remoteCandidates <span class="p_word">and</span> len(self.remoteCandidates)&gt;<span class="p_number">0</span>:
                self.retryNextCandidate()
            <span class="p_word">else</span>:
                self.receivedResponse(<span class="p_word">None</span>, Message.createResponse(<span class="p_number">408</span>, <span class="p_string">'Request timeout'</span>, <span class="p_word">None</span>, <span class="p_word">None</span>, self.request))
    
    <span class="p_word">def</span> error(self, transaction, error):
        <span class="p_triple">'''A transaction gave transport error.'''</span>
        <span class="p_word">if</span> transaction <span class="p_word">and</span> transaction != self.transaction: <span class="p_commentline"># invalid transaction</span>
            <span class="p_word">return</span>
        self.transaction = <span class="p_word">None</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.server: <span class="p_commentline"># UAC</span>
            <span class="p_word">if</span> self.remoteCandidates <span class="p_word">and</span> len(self.remoteCandidates)&gt;<span class="p_number">0</span>:
                self.retryNextCandidate()
            <span class="p_word">else</span>:
                self.receivedResponse(<span class="p_word">None</span>, Message.createResponse(<span class="p_number">503</span>, <span class="p_string">'Service unavailable - '</span> + error, <span class="p_word">None</span>, <span class="p_word">None</span>, self.request))

    <span class="p_word">def</span> authenticate(self, response, transaction):
        <span class="p_triple">'''Whether we can supply the credentials locally to authenticate or not?
        If we can, then re-send the request in new transaction and return true, else return false'''</span>
        a = response.first(<span class="p_string">'WWW-Authenticate'</span>) <span class="p_word">or</span> response.first(<span class="p_string">'Proxy-Authenticate'</span>) <span class="p_word">or</span> <span class="p_word">None</span>
        <span class="p_word">if</span> <span class="p_word">not</span> a: 
            <span class="p_word">return</span> False
        request = Message(str(transaction.request)) <span class="p_commentline"># construct a new message</span>
        
        resend, present = False, False
        <span class="p_word">for</span> b <span class="p_word">in</span> request.all(<span class="p_string">'Authorization'</span>, <span class="p_string">'Proxy-Authorization'</span>):
            <span class="p_word">if</span> a.realm == b.realm <span class="p_word">and</span> (a.name == <span class="p_string">'WWW-Authenticate'</span> <span class="p_word">and</span> b.name == <span class="p_string">'Authorization'</span> <span class="p_word">or</span> a.name == <span class="p_string">'Proxy-Authenticate'</span> <span class="p_word">and</span> b.name == <span class="p_string">'Proxy-Authorization'</span>):
                present = True
                <span class="p_word">break</span>

        <span class="p_word">if</span> <span class="p_word">not</span> present <span class="p_word">and</span> <span class="p_string">'realm'</span> <span class="p_word">in</span> a: <span class="p_commentline"># prompt for password</span>
            result = self.stack.authenticate(self, a)
            <span class="p_word">if</span> <span class="p_word">not</span> result <span class="p_word">or</span> <span class="p_string">'password'</span> <span class="p_word">not</span> <span class="p_word">in</span> a <span class="p_word">and</span> <span class="p_string">'hashValue'</span> <span class="p_word">not</span> <span class="p_word">in</span> a: 
                <span class="p_word">return</span> False
            value = createAuthorization(a.value, a.username, a.password, str(request.uri), self.request.method, self.request.body, self.auth)
            <span class="p_word">if</span> value:
                request.insert(Header(value, (a.name == <span class="p_string">'WWW-Authenticate'</span>) <span class="p_word">and</span> <span class="p_string">'Authorization'</span> <span class="p_word">or</span> <span class="p_string">'Proxy-Authorization'</span>), True)
                resend = True
        
        <span class="p_word">if</span> resend:
            self.localSeq = self.localSeq + <span class="p_number">1</span>
            request.CSeq = Header(str(self.localSeq) + <span class="p_string">' '</span> + request.method, <span class="p_string">'CSeq'</span>)
            request.first(<span class="p_string">'Via'</span>).branch = Transaction.createBranch(request, False) 
            self.request = request
            self.transaction = Transaction.createClient(self.stack, self, self.request, self.transaction.transport, self.transaction.remote)
            <span class="p_word">return</span> True
        <span class="p_word">else</span>:
            <span class="p_word">return</span> False;
    

</PRE><DIV class="commentbox">From RFC3261 p.69<pre>12 Dialogs

   A key concept for a user agent is that of a dialog.  A dialog
   represents a peer-to-peer SIP relationship between two user agents
   that persists for some time.  The dialog facilitates sequencing of
   messages between the user agents and proper routing of requests
   between both of them.  The dialog represents a context in which to
   interpret SIP messages.  Section 8 discussed method independent UA
   processing for requests and responses outside of a dialog.  This
   section discusses how those requests and responses are used to
   construct a dialog, and then how subsequent requests and responses
   are sent within a dialog.

   A dialog is identified at each UA with a dialog ID, which consists of
   a Call-ID value, a local tag and a remote tag.  The dialog ID at each
   UA involved in the dialog is not the same.  Specifically, the local
   tag at one UA is identical to the remote tag at the peer UA.  The
   tags are opaque tokens that facilitate the generation of unique
   dialog IDs.

   A dialog ID is also associated with all responses and with any
   request that contains a tag in the To field.  The rules for computing
   the dialog ID of a message depend on whether the SIP element is a UAC
   or UAS.  For a UAC, the Call-ID value of the dialog ID is set to the
   Call-ID of the message, the remote tag is set to the tag in the To
   field of the message, and the local tag is set to the tag in the From
   field of the message (these rules apply to both requests and
   responses).  As one would expect for a UAS, the Call-ID value of the
   dialog ID is set to the Call-ID of the message, the remote tag is set
   to the tag in the From field of the message, and the local tag is set
   to the tag in the To field of the message.

   A dialog contains certain pieces of state needed for further message
   transmissions within the dialog.  This state consists of the dialog
   ID, a local sequence number (used to order requests from the UA to
   its peer), a remote sequence number (used to order requests from its
   peer to the UA), a local URI, a remote URI, remote target, a boolean
   flag called "secure", and a route set, which is an ordered list of
   URIs.  The route set is the list of servers that need to be traversed
   to send a request to the peer.  A dialog can also be in the "early"
   state, which occurs when it is created with a provisional response,
   and then transition to the "confirmed" state when a 2xx final
   response arrives.  For other responses, or if no response arrives at
   all on that dialog, the early dialog terminates.</pre></DIV><PRE>
<span class="p_word">class</span> Dialog(UserAgent):
    <span class="p_triple">'''A SIP dialog'''</span>

</PRE><DIV class="commentbox">From RFC3261 p.70<pre>12.1 Creation of a Dialog

   Dialogs are created through the generation of non-failure responses
   to requests with specific methods.  Within this specification, only
   2xx and 101-199 responses with a To tag, where the request was
   INVITE, will establish a dialog.  A dialog established by a non-final
   response to a request is in the "early" state and it is called an
   early dialog.  Extensions MAY define other means for creating
   dialogs.  Section 13 gives more details that are specific to the
   INVITE method.  Here, we describe the process for creation of dialog
   state that is not dependent on the method.

   UAs MUST assign values to the dialog ID components as described
   below.

12.1.1 UAS behavior

   When a UAS responds to a request with a response that establishes a
   dialog (such as a 2xx to INVITE), the UAS MUST copy all Record-Route
   header field values from the request into the response (including the
   URIs, URI parameters, and any Record-Route header field parameters,
   whether they are known or unknown to the UAS) and MUST maintain the
   order of those values.  The UAS MUST add a Contact header field to
   the response.  The Contact header field contains an address where the
   UAS would like to be contacted for subsequent requests in the dialog
   (which includes the ACK for a 2xx response in the case of an INVITE).
   Generally, the host portion of this URI is the IP address or FQDN of
   the host.  The URI provided in the Contact header field MUST be a SIP
   or SIPS URI.  If the request that initiated the dialog contained a
   SIPS URI in the Request-URI or in the top Record-Route header field
   value, if there was any, or the Contact header field if there was no
   Record-Route header field, the Contact header field in the response
   MUST be a SIPS URI.  The URI SHOULD have global scope (that is, the
   same URI can be used in messages outside this dialog).  The same way,
   the scope of the URI in the Contact header field of the INVITE is not
   limited to this dialog either.  It can therefore be used in messages
   to the UAC even outside this dialog.

   The UAS then constructs the state of the dialog.  This state MUST be
   maintained for the duration of the dialog.

   If the request arrived over TLS, and the Request-URI contained a SIPS
   URI, the "secure" flag is set to TRUE.

   The route set MUST be set to the list of URIs in the Record-Route
   header field from the request, taken in order and preserving all URI
   parameters.  If no Record-Route header field is present in the
   request, the route set MUST be set to the empty set.  This route set,
   even if empty, overrides any pre-existing route set for future
   requests in this dialog.  The remote target MUST be set to the URI
   from the Contact header field of the request.

   The remote sequence number MUST be set to the value of the sequence
   number in the CSeq header field of the request.  The local sequence
   number MUST be empty.  The call identifier component of the dialog ID
   MUST be set to the value of the Call-ID in the request.  The local
   tag component of the dialog ID MUST be set to the tag in the To field
   in the response to the request (which always includes a tag), and the
   remote tag component of the dialog ID MUST be set to the tag from the
   From field in the request.  A UAS MUST be prepared to receive a
   request without a tag in the From field, in which case the tag is
   considered to have a value of null.

      This is to maintain backwards compatibility with RFC 2543, which
      did not mandate From tags.

   The remote URI MUST be set to the URI in the From field, and the
   local URI MUST be set to the URI in the To field.</pre></DIV><PRE>
    @staticmethod
    <span class="p_word">def</span> createServer(stack, request, response, transaction):
        <span class="p_triple">'''Create a dialog from UAS while sending response to request in the transaction.'''</span>
        d = Dialog(stack, request, True)
        d.request = request
        d.routeSet = request.all(<span class="p_string">'Record-Route'</span>) <span class="p_word">if</span> request[<span class="p_string">'Record-Route'</span>] <span class="p_word">else</span> <span class="p_word">None</span>
        <span class="p_word">while</span> d.routeSet <span class="p_word">and</span> isMulticast(d.routeSet[<span class="p_number">0</span>].value.uri.host): <span class="p_commentline"># remove any multicast address from top of the list.</span>
            <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'deleting top multicast routeSet'</span>, d.routeSet[<span class="p_number">0</span>]
            <span class="p_word">del</span> d.routeSet[<span class="p_number">0</span>]
            <span class="p_word">if</span> len(d.routeSet) == <span class="p_number">0</span>: d.routeSet = <span class="p_word">None</span> 
        d.secure = request.uri.secure
        d.localSeq, d.localSeq = <span class="p_number">0</span>, request.CSeq.number
        d.callId = request[<span class="p_string">'Call-ID'</span>].value
        d.localTag, d.remoteTag = response.To.tag, request.From.tag
        d.localParty, d.remoteParty = Address(str(request.To.value)), Address(str(request.From.value))
        d.remoteTarget = URI(str(request.first(<span class="p_string">'Contact'</span>).value.uri))
        <span class="p_commentline"># TODO: retransmission timer for 2xx in UAC</span>
        stack.dialogs[d.id] = d
        <span class="p_word">return</span> d
    

</PRE><DIV class="commentbox">From RFC3261 p.71<pre>12.1.2 UAC Behavior

   When a UAC sends a request that can establish a dialog (such as an
   INVITE) it MUST provide a SIP or SIPS URI with global scope (i.e.,
   the same SIP URI can be used in messages outside this dialog) in the
   Contact header field of the request.  If the request has a Request-
   URI or a topmost Route header field value with a SIPS URI, the
   Contact header field MUST contain a SIPS URI.
   When a UAC receives a response that establishes a dialog, it
   constructs the state of the dialog.  This state MUST be maintained
   for the duration of the dialog.

   If the request was sent over TLS, and the Request-URI contained a
   SIPS URI, the "secure" flag is set to TRUE.

   The route set MUST be set to the list of URIs in the Record-Route
   header field from the response, taken in reverse order and preserving
   all URI parameters.  If no Record-Route header field is present in
   the response, the route set MUST be set to the empty set.  This route
   set, even if empty, overrides any pre-existing route set for future
   requests in this dialog.  The remote target MUST be set to the URI
   from the Contact header field of the response.

   The local sequence number MUST be set to the value of the sequence
   number in the CSeq header field of the request.  The remote sequence
   number MUST be empty (it is established when the remote UA sends a
   request within the dialog).  The call identifier component of the
   dialog ID MUST be set to the value of the Call-ID in the request.
   The local tag component of the dialog ID MUST be set to the tag in
   the From field in the request, and the remote tag component of the
   dialog ID MUST be set to the tag in the To field of the response.  A
   UAC MUST be prepared to receive a response without a tag in the To
   field, in which case the tag is considered to have a value of null.

      This is to maintain backwards compatibility with RFC 2543, which
      did not mandate To tags.

   The remote URI MUST be set to the URI in the To field, and the local
   URI MUST be set to the URI in the From field.</pre></DIV><PRE>
    @staticmethod
    <span class="p_word">def</span> createClient(stack, request, response, transaction):
        <span class="p_triple">'''Create a dialog from UAC on receiving response to request in the transaction.'''</span>
        d = Dialog(stack, request, False)
        d.request = request
        d.routeSet = [x <span class="p_word">for</span> x <span class="p_word">in</span> reversed(response.all(<span class="p_string">'Record-Route'</span>))] <span class="p_word">if</span> response[<span class="p_string">'Record-Route'</span>] <span class="p_word">else</span> <span class="p_word">None</span>
        <span class="p_commentline">#print 'UAC routeSet=', d.routeSet</span>
        d.secure = request.uri.secure
        d.localSeq, d.remoteSeq = request.CSeq.number, <span class="p_number">0</span>
        d.callId = request[<span class="p_string">'Call-ID'</span>].value
        d.localTag, d.remoteTag = request.From.tag, response.To.tag
        d.localParty, d.remoteParty = Address(str(request.From.value)), Address(str(request.To.value))
        d.remoteTarget = URI(str(response.first(<span class="p_string">"Contact"</span>).value.uri))
        stack.dialogs[d.id] = d
        <span class="p_word">return</span> d

    @staticmethod
    <span class="p_word">def</span> extractId(m):
        <span class="p_triple">'''Extract dialog identifier string from a Message m.'''</span>
        <span class="p_word">return</span> m[<span class="p_string">'Call-ID'</span>].value + <span class="p_string">'|'</span> + (m.To.tag <span class="p_word">if</span> m.method <span class="p_word">else</span> m.From.tag) + <span class="p_string">'|'</span> + (m.From.tag <span class="p_word">if</span> m.method <span class="p_word">else</span> m.To.tag)
    
    <span class="p_word">def</span> __init__(self, stack, request, server, transaction=<span class="p_word">None</span>):
        <span class="p_triple">'''Create a dialog for the request in server (True) or client (False) mode for given transaction.'''</span>
        UserAgent.__init__(self, stack, request, server) <span class="p_commentline"># base class method</span>
        self.servers, self.clients = [], [] <span class="p_commentline"># pending server and client transactions</span>
        self._id = <span class="p_word">None</span>
        <span class="p_word">if</span> transaction: transaction.app = self <span class="p_commentline"># this is higher layer of transaction</span>

    <span class="p_word">def</span> close(self):
        <span class="p_word">if</span> self.stack: 
            <span class="p_word">if</span> self.id <span class="p_word">in</span> self.stack.dialogs: <span class="p_word">del</span> self.stack.dialogs[self.id]
            <span class="p_commentline"># self.stack = None # TODO: uncomment this to clear reference, but then it causes problem in receivedResponse where self.stack becomes None</span>
            
    @property
    <span class="p_word">def</span> id(self):
        <span class="p_triple">'''Dialog identifier string.'''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self._id: self._id = self.callId + <span class="p_string">'|'</span> + self.localTag + <span class="p_string">'|'</span> + self.remoteTag
        <span class="p_word">return</span> self._id


</PRE><DIV class="commentbox">From RFC3261 p.73<pre>12.2.1 UAC Behavior

12.2.1.1 Generating the Request

   A request within a dialog is constructed by using many of the
   components of the state stored as part of the dialog.

   The URI in the To field of the request MUST be set to the remote URI
   from the dialog state.  The tag in the To header field of the request
   MUST be set to the remote tag of the dialog ID.  The From URI of the
   request MUST be set to the local URI from the dialog state.  The tag
   in the From header field of the request MUST be set to the local tag
   of the dialog ID.  If the value of the remote or local tags is null,
   the tag parameter MUST be omitted from the To or From header fields,
   respectively.

      Usage of the URI from the To and From fields in the original
      request within subsequent requests is done for backwards
      compatibility with RFC 2543, which used the URI for dialog
      identification.  In this specification, only the tags are used for
      dialog identification.  It is expected that mandatory reflection
      of the original To and From URI in mid-dialog requests will be
      deprecated in a subsequent revision of this specification.

   The Call-ID of the request MUST be set to the Call-ID of the dialog.
   Requests within a dialog MUST contain strictly monotonically
   increasing and contiguous CSeq sequence numbers (increasing-by-one)
   in each direction (excepting ACK and CANCEL of course, whose numbers
   equal the requests being acknowledged or cancelled).  Therefore, if
   the local sequence number is not empty, the value of the local
   sequence number MUST be incremented by one, and this value MUST be
   placed into the CSeq header field.  If the local sequence number is
   empty, an initial value MUST be chosen using the guidelines of
   Section 8.1.1.5.  The method field in the CSeq header field value
   MUST match the method of the request.


      With a length of 32 bits, a client could generate, within a single
      call, one request a second for about 136 years before needing to
      wrap around.  The initial value of the sequence number is chosen
      so that subsequent requests within the same call will not wrap
      around.  A non-zero initial value allows clients to use a time-
      based initial sequence number.  A client could, for example,
      choose the 31 most significant bits of a 32-bit second clock as an
      initial sequence number.

   The UAC uses the remote target and route set to build the Request-URI
   and Route header field of the request.

   If the route set is empty, the UAC MUST place the remote target URI
   into the Request-URI.  The UAC MUST NOT add a Route header field to
   the request.

   If the route set is not empty, and the first URI in the route set
   contains the lr parameter (see Section 19.1.1), the UAC MUST place
   the remote target URI into the Request-URI and MUST include a Route
   header field containing the route set values in order, including all
   parameters.

   If the route set is not empty, and its first URI does not contain the
   lr parameter, the UAC MUST place the first URI from the route set
   into the Request-URI, stripping any parameters that are not allowed
   in a Request-URI.  The UAC MUST add a Route header field containing
   the remainder of the route set values in order, including all
   parameters.  The UAC MUST then place the remote target URI into the
   Route header field as the last value.

   For example, if the remote target is sip:user@remoteua and the route
   set contains:

      &amp;lt;sip:proxy1&amp;gt;,&amp;lt;sip:proxy2&amp;gt;,&amp;lt;sip:proxy3;lr&amp;gt;,&amp;lt;sip:proxy4&amp;gt;

   The request will be formed with the following Request-URI and Route
   header field:

   METHOD sip:proxy1
   Route: &amp;lt;sip:proxy2&amp;gt;,&amp;lt;sip:proxy3;lr&amp;gt;,&amp;lt;sip:proxy4&amp;gt;,&amp;lt;sip:user@remoteua&amp;gt;

      If the first URI of the route set does not contain the lr
      parameter, the proxy indicated does not understand the routing
      mechanisms described in this document and will act as specified in
      RFC 2543, replacing the Request-URI with the first Route header
      field value it receives while forwarding the message.  Placing the
      Request-URI at the end of the Route header field preserves the

      information in that Request-URI across the strict router (it will
      be returned to the Request-URI when the request reaches a loose-
      router).

   A UAC SHOULD include a Contact header field in any target refresh
   requests within a dialog, and unless there is a need to change it,
   the URI SHOULD be the same as used in previous requests within the
   dialog.  If the "secure" flag is true, that URI MUST be a SIPS URI.
   As discussed in Section 12.2.2, a Contact header field in a target
   refresh request updates the remote target URI.  This allows a UA to
   provide a new contact address, should its address change during the
   duration of the dialog.

   However, requests that are not target refresh requests do not affect
   the remote target URI for the dialog.

   The rest of the request is formed as described in Section 8.1.1.

   Once the request has been constructed, the address of the server is
   computed and the request is sent, using the same procedures for
   requests outside of a dialog (Section 8.1.2).

      The procedures in Section 8.1.2 will normally result in the
      request being sent to the address indicated by the topmost Route
      header field value or the Request-URI if no Route header field is
      present.  Subject to certain restrictions, they allow the request
      to be sent to an alternate address (such as a default outbound
      proxy not represented in the route set).
</pre></DIV><PRE>
    <span class="p_word">def</span> createRequest(self, method, content=<span class="p_word">None</span>, contentType=<span class="p_word">None</span>):
        <span class="p_triple">'''Create a new SIP request in this dialog.'''</span> 
        request = UserAgent.createRequest(self, method, content, contentType)
        <span class="p_word">if</span> self.remoteTag: request.To.tag = self.remoteTag
        <span class="p_word">if</span> self.routeSet <span class="p_word">and</span> len(self.routeSet)&gt;<span class="p_number">0</span> <span class="p_word">and</span> <span class="p_string">'lr'</span> <span class="p_word">not</span> <span class="p_word">in</span> self.routeSet[<span class="p_number">0</span>].value.uri.param: <span class="p_commentline"># strict route</span>
            request.uri = self.routeSet[<span class="p_number">0</span>].value.uri.dup()
            <span class="p_word">del</span> request.uri.param[<span class="p_string">'lr'</span>]
        <span class="p_word">return</span> request
    
    <span class="p_word">def</span> createResponse(self, response, responsetext, content=<span class="p_word">None</span>, contentType=<span class="p_word">None</span>):
        <span class="p_triple">'''Create a new SIP response in this dialog'''</span>
        <span class="p_word">if</span> len(self.servers) == <span class="p_number">0</span>: <span class="p_word">raise</span> ValueError, <span class="p_string">'No server transaction to create response'</span>
        request = self.servers[<span class="p_number">0</span>].request
        response = Message.createResponse(response, responsetext, <span class="p_word">None</span>, content, request)
        <span class="p_word">if</span> contentType: response[<span class="p_string">'Content-Type'</span>] = Header(contentType, <span class="p_string">'Content-Type'</span>)
        <span class="p_word">if</span> response.response != <span class="p_number">100</span> <span class="p_word">and</span> <span class="p_string">'tag'</span> <span class="p_word">not</span> <span class="p_word">in</span> response.To:
            response.To.tag = self.localTag
        <span class="p_word">return</span> response

    <span class="p_word">def</span> sendResponse(self, response, responsetext=<span class="p_word">None</span>, content=<span class="p_word">None</span>, contentType=<span class="p_word">None</span>, createDialog=True):
        <span class="p_triple">'''Send a new response in this dialog for first pending server transaction.'''</span>
        <span class="p_word">if</span> len(self.servers) == <span class="p_number">0</span>: <span class="p_word">raise</span> ValueError, <span class="p_string">'No server transaction to send response'</span>
        self.transaction, self.request = self.servers[<span class="p_number">0</span>], self.servers[<span class="p_number">0</span>].request
        UserAgent.sendResponse(self, response, responsetext, content, contentType, False)
        code = response <span class="p_word">if</span> isinstance(response, int) <span class="p_word">else</span> response.response
        <span class="p_word">if</span> code &gt;= <span class="p_number">200</span>:
            self.servers.pop(<span class="p_number">0</span>) <span class="p_commentline"># no more pending if final response sent</span>

    <span class="p_word">def</span> sendCancel(self):
        <span class="p_triple">'''Send a CANCEL request for the first pending client transaction.'''</span>
        <span class="p_word">if</span> len(self.clients) == <span class="p_number">0</span>: 
            <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'No client transaction to send cancel'</span>
            <span class="p_word">return</span>
        self.transaction, self.request = self.clients[<span class="p_number">0</span>], self.clients[<span class="p_number">0</span>].request
        UserAgent.sendCancel(self)


</PRE><DIV class="commentbox">From RFC3261 p.76<pre>12.2.2 UAS Behavior

   Requests sent within a dialog, as any other requests, are atomic.  If
   a particular request is accepted by the UAS, all the state changes
   associated with it are performed.  If the request is rejected, none
   of the state changes are performed.

      Note that some requests, such as INVITEs, affect several pieces of
      state.

   The UAS will receive the request from the transaction layer.  If the
   request has a tag in the To header field, the UAS core computes the
   dialog identifier corresponding to the request and compares it with
   existing dialogs.  If there is a match, this is a mid-dialog request.
   In that case, the UAS first applies the same processing rules for
   requests outside of a dialog, discussed in Section 8.2.

   If the request has a tag in the To header field, but the dialog
   identifier does not match any existing dialogs, the UAS may have
   crashed and restarted, or it may have received a request for a
   different (possibly failed) UAS (the UASs can construct the To tags
   so that a UAS can identify that the tag was for a UAS for which it is
   providing recovery).  Another possibility is that the incoming
   request has been simply misrouted.  Based on the To tag, the UAS MAY
   either accept or reject the request.  Accepting the request for
   acceptable To tags provides robustness, so that dialogs can persist
   even through crashes.  UAs wishing to support this capability must
   take into consideration some issues such as choosing monotonically
   increasing CSeq sequence numbers even across reboots, reconstructing
   the route set, and accepting out-of-range RTP timestamps and sequence
   numbers.

   If the UAS wishes to reject the request because it does not wish to
   recreate the dialog, it MUST respond to the request with a 481
   (Call/Transaction Does Not Exist) status code and pass that to the
   server transaction.



   Requests that do not change in any way the state of a dialog may be
   received within a dialog (for example, an OPTIONS request).  They are
   processed as if they had been received outside the dialog.

   If the remote sequence number is empty, it MUST be set to the value
   of the sequence number in the CSeq header field value in the request.
   If the remote sequence number was not empty, but the sequence number
   of the request is lower than the remote sequence number, the request
   is out of order and MUST be rejected with a 500 (Server Internal
   Error) response.  If the remote sequence number was not empty, and
   the sequence number of the request is greater than the remote
   sequence number, the request is in order.  It is possible for the
   CSeq sequence number to be higher than the remote sequence number by
   more than one.  This is not an error condition, and a UAS SHOULD be
   prepared to receive and process requests with CSeq values more than
   one higher than the previous received request.  The UAS MUST then set
   the remote sequence number to the value of the sequence number in the
   CSeq header field value in the request.

      If a proxy challenges a request generated by the UAC, the UAC has
      to resubmit the request with credentials.  The resubmitted request
      will have a new CSeq number.  The UAS will never see the first
      request, and thus, it will notice a gap in the CSeq number space.
      Such a gap does not represent any error condition.

   When a UAS receives a target refresh request, it MUST replace the
   dialog's remote target URI with the URI from the Contact header field
   in that request, if present.</pre></DIV><PRE>
    <span class="p_word">def</span> receivedRequest(self, transaction, request):
        <span class="p_triple">'''Incoming request in the dialog.'''</span>
        <span class="p_word">if</span> self.remoteSeq != <span class="p_number">0</span> <span class="p_word">and</span> request.CSeq.number &lt; self.remoteSeq:
            <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'Dialog.receivedRequest() CSeq is old'</span>, request.CSeq.number, <span class="p_string">'&lt;'</span>, self.remoteSeq
            self.sendResponse(<span class="p_number">500</span>, <span class="p_string">'Internal server error - invalid CSeq'</span>)
            <span class="p_word">return</span>
        self.remoteSeq = request.CSeq.number
        
        <span class="p_word">if</span> request.method == <span class="p_string">'INVITE'</span> <span class="p_word">and</span> request.Contect:
            self.remoteTarget = request.first(<span class="p_string">'Contact'</span>).value.uri.dup()
        
        <span class="p_word">if</span> request.method == <span class="p_string">'ACK'</span> <span class="p_word">or</span> request.method == <span class="p_string">'CANCEL'</span>:
            self.servers = filter(<span class="p_word">lambda</span> x: x != transaction, self.servers) <span class="p_commentline"># remove from pending</span>
            <span class="p_word">if</span> request.method == <span class="p_string">'ACK'</span>: 
                self.stack.receivedRequest(self, request)
            <span class="p_word">else</span>:
                self.stack.cancelled(self, transaction.request)
            <span class="p_word">return</span>
        
        self.servers.append(transaction) <span class="p_commentline"># make it pending</span>
        self.stack.receivedRequest(self, request)


</PRE><DIV class="commentbox">From RFC3261 p.75<pre>12.2.1.2 Processing the Responses

   The UAC will receive responses to the request from the transaction
   layer.  If the client transaction returns a timeout, this is treated
   as a 408 (Request Timeout) response.

   The behavior of a UAC that receives a 3xx response for a request sent
   within a dialog is the same as if the request had been sent outside a
   dialog.  This behavior is described in Section 8.1.3.4.

      Note, however, that when the UAC tries alternative locations, it
      still uses the route set for the dialog to build the Route header
      of the request.

   When a UAC receives a 2xx response to a target refresh request, it
   MUST replace the dialog's remote target URI with the URI from the
   Contact header field in that response, if present.


   If the response for a request within a dialog is a 481
   (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
   SHOULD terminate the dialog.  A UAC SHOULD also terminate a dialog if
   no response at all is received for the request (the client
   transaction would inform the TU about the timeout.)

      For INVITE initiated dialogs, terminating the dialog consists of
      sending a BYE.</pre></DIV><PRE>
    <span class="p_word">def</span> receivedResponse(self, transaction, response):
        <span class="p_triple">'''Incoming response in a dialog.'''</span>
        <span class="p_word">if</span> response.is2xx <span class="p_word">and</span> response.Contact <span class="p_word">and</span> transaction <span class="p_word">and</span> transaction.request.method == <span class="p_string">'INVITE'</span>:
            self.remoteTarget = response.first(<span class="p_string">'Contact'</span>).value.uri.dup()
        <span class="p_word">if</span> <span class="p_word">not</span> response.is1xx: <span class="p_commentline"># final response</span>
            self.clients = filter(<span class="p_word">lambda</span> x: x != transaction, self.clients) <span class="p_commentline"># remove from pending</span>
        
        <span class="p_word">if</span> response.response == <span class="p_number">408</span> <span class="p_word">or</span> response.response == <span class="p_number">481</span>: <span class="p_commentline"># remote doesn't recognize the dialog</span>
            self.close() 
            
        <span class="p_word">if</span> response.response == <span class="p_number">401</span> <span class="p_word">or</span> response.response == <span class="p_number">407</span>:
            <span class="p_word">if</span> <span class="p_word">not</span> self.authenticate(response, transaction):
                self.stack.receivedResponse(self, response)
        <span class="p_word">elif</span> transaction:
            self.stack.receivedResponse(self, response)
        
        <span class="p_word">if</span> self.autoack <span class="p_word">and</span> response.is2xx <span class="p_word">and</span> (transaction <span class="p_word">and</span> transaction.request.method == <span class="p_string">'INVITE'</span> <span class="p_word">or</span> response.CSeq.method == <span class="p_string">'INVITE'</span>):
            self.sendRequest(self.createRequest(<span class="p_string">'ACK'</span>))

<span class="p_commentline">#---------------------------Proxy-------------------------------------------</span>


</PRE><DIV class="commentbox">From RFC3261 p.91<pre>16 Proxy Behavior

16.1 Overview

   SIP proxies are elements that route SIP requests to user agent
   servers and SIP responses to user agent clients.  A request may
   traverse several proxies on its way to a UAS.  Each will make routing
   decisions, modifying the request before forwarding it to the next
   element.  Responses will route through the same set of proxies
   traversed by the request in the reverse order.

   Being a proxy is a logical role for a SIP element.  When a request
   arrives, an element that can play the role of a proxy first decides
   if it needs to respond to the request on its own.  For instance, the
   request may be malformed or the element may need credentials from the
   client before acting as a proxy.  The element MAY respond with any

   appropriate error code.  When responding directly to a request, the
   element is playing the role of a UAS and MUST behave as described in
   Section 8.2.

   A proxy can operate in either a stateful or stateless mode for each
   new request.  When stateless, a proxy acts as a simple forwarding
   element.  It forwards each request downstream to a single element
   determined by making a targeting and routing decision based on the
   request.  It simply forwards every response it receives upstream.  A
   stateless proxy discards information about a message once the message
   has been forwarded.  A stateful proxy remembers information
   (specifically, transaction state) about each incoming request and any
   requests it sends as a result of processing the incoming request.  It
   uses this information to affect the processing of future messages
   associated with that request.  A stateful proxy MAY choose to "fork"
   a request, routing it to multiple destinations.  Any request that is
   forwarded to more than one location MUST be handled statefully.

   In some circumstances, a proxy MAY forward requests using stateful
   transports (such as TCP) without being transaction-stateful.  For
   instance, a proxy MAY forward a request from one TCP connection to
   another transaction statelessly as long as it places enough
   information in the message to be able to forward the response down
   the same connection the request arrived on.  Requests forwarded
   between different types of transports where the proxy's TU must take
   an active role in ensuring reliable delivery on one of the transports
   MUST be forwarded transaction statefully.

   A stateful proxy MAY transition to stateless operation at any time
   during the processing of a request, so long as it did not do anything
   that would otherwise prevent it from being stateless initially
   (forking, for example, or generation of a 100 response).  When
   performing such a transition, all state is simply discarded.  The
   proxy SHOULD NOT initiate a CANCEL request.

   Much of the processing involved when acting statelessly or statefully
   for a request is identical.  The next several subsections are written
   from the point of view of a stateful proxy.  The last section calls
   out those places where a stateless proxy behaves differently.

16.2 Stateful Proxy

   When stateful, a proxy is purely a SIP transaction processing engine.
   Its behavior is modeled here in terms of the server and client
   transactions defined in Section 17.  A stateful proxy has a server
   transaction associated with one or more client transactions by a
   higher layer proxy processing component (see figure 3), known as a
   proxy core.  An incoming request is processed by a server
   transaction.  Requests from the server transaction are passed to a
   proxy core.  The proxy core determines where to route the request,
   choosing one or more next-hop locations.  An outgoing request for
   each next-hop location is processed by its own associated client
   transaction.  The proxy core collects the responses from the client
   transactions and uses them to send responses to the server
   transaction.

   A stateful proxy creates a new server transaction for each new
   request received.  Any retransmissions of the request will then be
   handled by that server transaction per Section 17.  The proxy core
   MUST behave as a UAS with respect to sending an immediate provisional
   on that server transaction (such as 100 Trying) as described in
   Section 8.2.6.  Thus, a stateful proxy SHOULD NOT generate 100
   (Trying) responses to non-INVITE requests.

   This is a model of proxy behavior, not of software.  An
   implementation is free to take any approach that replicates the
   external behavior this model defines.

   For all new requests, including any with unknown methods, an element
   intending to proxy the request MUST:

      1. Validate the request (Section 16.3)

      2. Preprocess routing information (Section 16.4)

      3. Determine target(s) for the request (Section 16.5)

            +--------------------+
            |                    | +---+
            |                    | | C |
            |                    | | T |
            |                    | +---+
      +---+ |       Proxy        | +---+   CT = Client Transaction
      | S | |  "Higher" Layer    | | C |
      | T | |                    | | T |   ST = Server Transaction
      +---+ |                    | +---+
            |                    | +---+
            |                    | | C |
            |                    | | T |
            |                    | +---+
            +--------------------+

               Figure 3: Stateful Proxy Model



      4. Forward the request to each target (Section 16.6)

      5. Process all responses (Section 16.7)

16.3 Request Validation

   Before an element can proxy a request, it MUST verify the message's
   validity.  A valid message must pass the following checks:

      1. Reasonable Syntax

      2. URI scheme

      3. Max-Forwards

      4. (Optional) Loop Detection

      5. Proxy-Require

      6. Proxy-Authorization

   If any of these checks fail, the element MUST behave as a user agent
   server (see Section 8.2) and respond with an error code.

   Notice that a proxy is not required to detect merged requests and
   MUST NOT treat merged requests as an error condition.  The endpoints
   receiving the requests will resolve the merge as described in Section
   8.2.2.2.

   1. Reasonable syntax check

      The request MUST be well-formed enough to be handled with a server
      transaction.  Any components involved in the remainder of these
      Request Validation steps or the Request Forwarding section MUST be
      well-formed.  Any other components, well-formed or not, SHOULD be
      ignored and remain unchanged when the message is forwarded.  For
      instance, an element would not reject a request because of a
      malformed Date header field.  Likewise, a proxy would not remove a
      malformed Date header field before forwarding a request.

      This protocol is designed to be extended.  Future extensions may
      define new methods and header fields at any time.  An element MUST
      NOT refuse to proxy a request because it contains a method or
      header field it does not know about.




   2. URI scheme check

      If the Request-URI has a URI whose scheme is not understood by the
      proxy, the proxy SHOULD reject the request with a 416 (Unsupported
      URI Scheme) response.

   3. Max-Forwards check

      The Max-Forwards header field (Section 20.22) is used to limit the
      number of elements a SIP request can traverse.

      If the request does not contain a Max-Forwards header field, this
      check is passed.

      If the request contains a Max-Forwards header field with a field
      value greater than zero, the check is passed.

      If the request contains a Max-Forwards header field with a field
      value of zero (0), the element MUST NOT forward the request.  If
      the request was for OPTIONS, the element MAY act as the final
      recipient and respond per Section 11.  Otherwise, the element MUST
      return a 483 (Too many hops) response.

   4. Optional Loop Detection check

      An element MAY check for forwarding loops before forwarding a
      request.  If the request contains a Via header field with a sent-
      by value that equals a value placed into previous requests by the
      proxy, the request has been forwarded by this element before.  The
      request has either looped or is legitimately spiraling through the
      element.  To determine if the request has looped, the element MAY
      perform the branch parameter calculation described in Step 8 of
      Section 16.6 on this message and compare it to the parameter
      received in that Via header field.  If the parameters match, the
      request has looped.  If they differ, the request is spiraling, and
      processing continues.  If a loop is detected, the element MAY
      return a 482 (Loop Detected) response.

   5. Proxy-Require check

      Future extensions to this protocol may introduce features that
      require special handling by proxies.  Endpoints will include a
      Proxy-Require header field in requests that use these features,
      telling the proxy not to process the request unless the feature is
      understood.



      If the request contains a Proxy-Require header field (Section
      20.29) with one or more option-tags this element does not
      understand, the element MUST return a 420 (Bad Extension)
      response.  The response MUST include an Unsupported (Section
      20.40) header field listing those option-tags the element did not
      understand.

   6. Proxy-Authorization check

      If an element requires credentials before forwarding a request,
      the request MUST be inspected as described in Section 22.3.  That
      section also defines what the element must do if the inspection
      fails.

16.4 Route Information Preprocessing

   The proxy MUST inspect the Request-URI of the request.  If the
   Request-URI of the request contains a value this proxy previously
   placed into a Record-Route header field (see Section 16.6 item 4),
   the proxy MUST replace the Request-URI in the request with the last
   value from the Route header field, and remove that value from the
   Route header field.  The proxy MUST then proceed as if it received
   this modified request.

      This will only happen when the element sending the request to the
      proxy (which may have been an endpoint) is a strict router.  This
      rewrite on receive is necessary to enable backwards compatibility
      with those elements.  It also allows elements following this
      specification to preserve the Request-URI through strict-routing
      proxies (see Section 12.2.1.1).

      This requirement does not obligate a proxy to keep state in order
      to detect URIs it previously placed in Record-Route header fields.
      Instead, a proxy need only place enough information in those URIs
      to recognize them as values it provided when they later appear.

   If the Request-URI contains a maddr parameter, the proxy MUST check
   to see if its value is in the set of addresses or domains the proxy
   is configured to be responsible for.  If the Request-URI has a maddr
   parameter with a value the proxy is responsible for, and the request
   was received using the port and transport indicated (explicitly or by
   default) in the Request-URI, the proxy MUST strip the maddr and any
   non-default port or transport parameter and continue processing as if
   those values had not been present in the request.




      A request may arrive with a maddr matching the proxy, but on a
      port or transport different from that indicated in the URI.  Such
      a request needs to be forwarded to the proxy using the indicated
      port and transport.

   If the first value in the Route header field indicates this proxy,
   the proxy MUST remove that value from the request.

16.5 Determining Request Targets

   Next, the proxy calculates the target(s) of the request.  The set of
   targets will either be predetermined by the contents of the request
   or will be obtained from an abstract location service.  Each target
   in the set is represented as a URI.

   If the Request-URI of the request contains an maddr parameter, the
   Request-URI MUST be placed into the target set as the only target
   URI, and the proxy MUST proceed to Section 16.6.

   If the domain of the Request-URI indicates a domain this element is
   not responsible for, the Request-URI MUST be placed into the target
   set as the only target, and the element MUST proceed to the task of
   Request Forwarding (Section 16.6).

      There are many circumstances in which a proxy might receive a
      request for a domain it is not responsible for.  A firewall proxy
      handling outgoing calls (the way HTTP proxies handle outgoing
      requests) is an example of where this is likely to occur.

   If the target set for the request has not been predetermined as
   described above, this implies that the element is responsible for the
   domain in the Request-URI, and the element MAY use whatever mechanism
   it desires to determine where to send the request.  Any of these
   mechanisms can be modeled as accessing an abstract Location Service.
   This may consist of obtaining information from a location service
   created by a SIP Registrar, reading a database, consulting a presence
   server, utilizing other protocols, or simply performing an
   algorithmic substitution on the Request-URI.  When accessing the
   location service constructed by a registrar, the Request-URI MUST
   first be canonicalized as described in Section 10.3 before being used
   as an index.  The output of these mechanisms is used to construct the
   target set.

   If the Request-URI does not provide sufficient information for the
   proxy to determine the target set, it SHOULD return a 485 (Ambiguous)
   response.  This response SHOULD contain a Contact header field
   containing URIs of new addresses to be tried.  For example, an INVITE

   to sip:John.Smith@company.com may be ambiguous at a proxy whose
   location service has multiple John Smiths listed.  See Section
   21.4.23 for details.

   Any information in or about the request or the current environment of
   the element MAY be used in the construction of the target set.  For
   instance, different sets may be constructed depending on contents or
   the presence of header fields and bodies, the time of day of the
   request's arrival, the interface on which the request arrived,
   failure of previous requests, or even the element's current level of
   utilization.

   As potential targets are located through these services, their URIs
   are added to the target set.  Targets can only be placed in the
   target set once.  If a target URI is already present in the set
   (based on the definition of equality for the URI type), it MUST NOT
   be added again.

   A proxy MUST NOT add additional targets to the target set if the
   Request-URI of the original request does not indicate a resource this
   proxy is responsible for.

      A proxy can only change the Request-URI of a request during
      forwarding if it is responsible for that URI.  If the proxy is not
      responsible for that URI, it will not recurse on 3xx or 416
      responses as described below.

   If the Request-URI of the original request indicates a resource this
   proxy is responsible for, the proxy MAY continue to add targets to
   the set after beginning Request Forwarding.  It MAY use any
   information obtained during that processing to determine new targets.
   For instance, a proxy may choose to incorporate contacts obtained in
   a redirect response (3xx) into the target set.  If a proxy uses a
   dynamic source of information while building the target set (for
   instance, if it consults a SIP Registrar), it SHOULD monitor that
   source for the duration of processing the request.  New locations
   SHOULD be added to the target set as they become available.  As
   above, any given URI MUST NOT be added to the set more than once.

      Allowing a URI to be added to the set only once reduces
      unnecessary network traffic, and in the case of incorporating
      contacts from redirect requests prevents infinite recursion.

   For example, a trivial location service is a "no-op", where the
   target URI is equal to the incoming request URI.  The request is sent
   to a specific next hop proxy for further processing.  During request


   forwarding of Section 16.6, Item 6, the identity of that next hop,
   expressed as a SIP or SIPS URI, is inserted as the top-most Route
   header field value into the request.

   If the Request-URI indicates a resource at this proxy that does not
   exist, the proxy MUST return a 404 (Not Found) response.

   If the target set remains empty after applying all of the above, the
   proxy MUST return an error response, which SHOULD be the 480
   (Temporarily Unavailable) response.

16.6 Request Forwarding

   As soon as the target set is non-empty, a proxy MAY begin forwarding
   the request.  A stateful proxy MAY process the set in any order.  It
   MAY process multiple targets serially, allowing each client
   transaction to complete before starting the next.  It MAY start
   client transactions with every target in parallel.  It also MAY
   arbitrarily divide the set into groups, processing the groups
   serially and processing the targets in each group in parallel.

   A common ordering mechanism is to use the qvalue parameter of targets
   obtained from Contact header fields (see Section 20.10).  Targets are
   processed from highest qvalue to lowest.  Targets with equal qvalues
   may be processed in parallel.

   A stateful proxy must have a mechanism to maintain the target set as
   responses are received and associate the responses to each forwarded
   request with the original request.  For the purposes of this model,
   this mechanism is a "response context" created by the proxy layer
   before forwarding the first request.

   For each target, the proxy forwards the request following these
   steps:

      1.  Make a copy of the received request

      2.  Update the Request-URI

      3.  Update the Max-Forwards header field

      4.  Optionally add a Record-route header field value

      5.  Optionally add additional header fields

      6.  Postprocess routing information

      7.  Determine the next-hop address, port, and transport
      8.  Add a Via header field value

      9.  Add a Content-Length header field if necessary

      10. Forward the new request

      11. Set timer C

   Each of these steps is detailed below:

      1. Copy request

         The proxy starts with a copy of the received request.  The copy
         MUST initially contain all of the header fields from the
         received request.  Fields not detailed in the processing
         described below MUST NOT be removed.  The copy SHOULD maintain
         the ordering of the header fields as in the received request.
         The proxy MUST NOT reorder field values with a common field
         name (See Section 7.3.1).  The proxy MUST NOT add to, modify,
         or remove the message body.

         An actual implementation need not perform a copy; the primary
         requirement is that the processing for each next hop begin with
         the same request.

      2. Request-URI

         The Request-URI in the copy's start line MUST be replaced with
         the URI for this target.  If the URI contains any parameters
         not allowed in a Request-URI, they MUST be removed.

         This is the essence of a proxy's role.  This is the mechanism
         through which a proxy routes a request toward its destination.

         In some circumstances, the received Request-URI is placed into
         the target set without being modified.  For that target, the
         replacement above is effectively a no-op.

      3. Max-Forwards

         If the copy contains a Max-Forwards header field, the proxy
         MUST decrement its value by one (1).

         If the copy does not contain a Max-Forwards header field, the
         proxy MUST add one with a field value, which SHOULD be 70.

         Some existing UAs will not provide a Max-Forwards header field
         in a request.
      4. Record-Route

         If this proxy wishes to remain on the path of future requests
         in a dialog created by this request (assuming the request
         creates a dialog), it MUST insert a Record-Route header field
         value into the copy before any existing Record-Route header
         field values, even if a Route header field is already present.

         Requests establishing a dialog may contain a preloaded Route
         header field.

         If this request is already part of a dialog, the proxy SHOULD
         insert a Record-Route header field value if it wishes to remain
         on the path of future requests in the dialog.  In normal
         endpoint operation as described in Section 12, these Record-
         Route header field values will not have any effect on the route
         sets used by the endpoints.

         The proxy will remain on the path if it chooses to not insert a
         Record-Route header field value into requests that are already
         part of a dialog.  However, it would be removed from the path
         when an endpoint that has failed reconstitutes the dialog.

         A proxy MAY insert a Record-Route header field value into any
         request.  If the request does not initiate a dialog, the
         endpoints will ignore the value.  See Section 12 for details on
         how endpoints use the Record-Route header field values to
         construct Route header fields.

         Each proxy in the path of a request chooses whether to add a
         Record-Route header field value independently - the presence of
         a Record-Route header field in a request does not obligate this
         proxy to add a value.

         The URI placed in the Record-Route header field value MUST be a
         SIP or SIPS URI.  This URI MUST contain an lr parameter (see
         Section 19.1.1).  This URI MAY be different for each
         destination the request is forwarded to.  The URI SHOULD NOT
         contain the transport parameter unless the proxy has knowledge
         (such as in a private network) that the next downstream element
         that will be in the path of subsequent requests supports that
         transport.

         The URI this proxy provides will be used by some other element
         to make a routing decision.  This proxy, in general, has no way
         of knowing the capabilities of that element, so it must
         restrict itself to the mandatory elements of a SIP
         implementation: SIP URIs and either the TCP or UDP transports.
         The URI placed in the Record-Route header field MUST resolve to
         the element inserting it (or a suitable stand-in) when the
         server location procedures of [4] are applied to it, so that
         subsequent requests reach the same SIP element.  If the
         Request-URI contains a SIPS URI, or the topmost Route header
         field value (after the post processing of bullet 6) contains a
         SIPS URI, the URI placed into the Record-Route header field
         MUST be a SIPS URI.  Furthermore, if the request was not
         received over TLS, the proxy MUST insert a Record-Route header
         field.  In a similar fashion, a proxy that receives a request
         over TLS, but generates a request without a SIPS URI in the
         Request-URI or topmost Route header field value (after the post
         processing of bullet 6), MUST insert a Record-Route header
         field that is not a SIPS URI.

         A proxy at a security perimeter must remain on the perimeter
         throughout the dialog.

         If the URI placed in the Record-Route header field needs to be
         rewritten when it passes back through in a response, the URI
         MUST be distinct enough to locate at that time.  (The request
         may spiral through this proxy, resulting in more than one
         Record-Route header field value being added).  Item 8 of
         Section 16.7 recommends a mechanism to make the URI
         sufficiently distinct.

         The proxy MAY include parameters in the Record-Route header
         field value.  These will be echoed in some responses to the
         request such as the 200 (OK) responses to INVITE.  Such
         parameters may be useful for keeping state in the message
         rather than the proxy.

         If a proxy needs to be in the path of any type of dialog (such
         as one straddling a firewall), it SHOULD add a Record-Route
         header field value to every request with a method it does not
         understand since that method may have dialog semantics.

         The URI a proxy places into a Record-Route header field is only
         valid for the lifetime of any dialog created by the transaction
         in which it occurs.  A dialog-stateful proxy, for example, MAY
         refuse to accept future requests with that value in the
         Request-URI after the dialog has terminated.  Non-dialog-
         stateful proxies, of course, have no concept of when the dialog
         has terminated, but they MAY encode enough information in the
         value to compare it against the dialog identifier of future
         requests and MAY reject requests not matching that information.
         Endpoints MUST NOT use a URI obtained from a Record-Route
         header field outside the dialog in which it was provided.  See
         Section 12 for more information on an endpoint's use of
         Record-Route header fields.

         Record-routing may be required by certain services where the
         proxy needs to observe all messages in a dialog.  However, it
         slows down processing and impairs scalability and thus proxies
         should only record-route if required for a particular service.

         The Record-Route process is designed to work for any SIP
         request that initiates a dialog.  INVITE is the only such
         request in this specification, but extensions to the protocol
         MAY define others.

      5. Add Additional Header Fields

         The proxy MAY add any other appropriate header fields to the
         copy at this point.

      6. Postprocess routing information

         A proxy MAY have a local policy that mandates that a request
         visit a specific set of proxies before being delivered to the
         destination.  A proxy MUST ensure that all such proxies are
         loose routers.  Generally, this can only be known with
         certainty if the proxies are within the same administrative
         domain.  This set of proxies is represented by a set of URIs
         (each of which contains the lr parameter).  This set MUST be
         pushed into the Route header field of the copy ahead of any
         existing values, if present.  If the Route header field is
         absent, it MUST be added, containing that list of URIs.

         If the proxy has a local policy that mandates that the request
         visit one specific proxy, an alternative to pushing a Route
         value into the Route header field is to bypass the forwarding
         logic of item 10 below, and instead just send the request to
         the address, port, and transport for that specific proxy.  If
         the request has a Route header field, this alternative MUST NOT
         be used unless it is known that next hop proxy is a loose
         router.  Otherwise, this approach MAY be used, but the Route
         insertion mechanism above is preferred for its robustness,
         flexibility, generality and consistency of operation.
         Furthermore, if the Request-URI contains a SIPS URI, TLS MUST
         be used to communicate with that proxy.

         If the copy contains a Route header field, the proxy MUST
         inspect the URI in its first value.  If that URI does not
         contain an lr parameter, the proxy MUST modify the copy as
         follows:
         -  The proxy MUST place the Request-URI into the Route header
            field as the last value.

         -  The proxy MUST then place the first Route header field value
            into the Request-URI and remove that value from the Route
            header field.

         Appending the Request-URI to the Route header field is part of
         a mechanism used to pass the information in that Request-URI
         through strict-routing elements.  "Popping" the first Route
         header field value into the Request-URI formats the message the
         way a strict-routing element expects to receive it (with its
         own URI in the Request-URI and the next location to visit in
         the first Route header field value).

      7. Determine Next-Hop Address, Port, and Transport

         The proxy MAY have a local policy to send the request to a
         specific IP address, port, and transport, independent of the
         values of the Route and Request-URI.  Such a policy MUST NOT be
         used if the proxy is not certain that the IP address, port, and
         transport correspond to a server that is a loose router.
         However, this mechanism for sending the request through a
         specific next hop is NOT RECOMMENDED; instead a Route header
         field should be used for that purpose as described above.

         In the absence of such an overriding mechanism, the proxy
         applies the procedures listed in [4] as follows to determine
         where to send the request.  If the proxy has reformatted the
         request to send to a strict-routing element as described in
         step 6 above, the proxy MUST apply those procedures to the
         Request-URI of the request.  Otherwise, the proxy MUST apply
         the procedures to the first value in the Route header field, if
         present, else the Request-URI.  The procedures will produce an
         ordered set of (address, port, transport) tuples.
         Independently of which URI is being used as input to the
         procedures of [4], if the Request-URI specifies a SIPS
         resource, the proxy MUST follow the procedures of [4] as if the
         input URI were a SIPS URI.

         As described in [4], the proxy MUST attempt to deliver the
         message to the first tuple in that set, and proceed through the
         set in order until the delivery attempt succeeds.

         For each tuple attempted, the proxy MUST format the message as
         appropriate for the tuple and send the request using a new
         client transaction as detailed in steps 8 through 10.

         Since each attempt uses a new client transaction, it represents
         a new branch.  Thus, the branch parameter provided with the Via
         header field inserted in step 8 MUST be different for each
         attempt.

         If the client transaction reports failure to send the request
         or a timeout from its state machine, the proxy continues to the
         next address in that ordered set.  If the ordered set is
         exhausted, the request cannot be forwarded to this element in
         the target set.  The proxy does not need to place anything in
         the response context, but otherwise acts as if this element of
         the target set returned a 408 (Request Timeout) final response.

      8. Add a Via header field value

         The proxy MUST insert a Via header field value into the copy
         before the existing Via header field values.  The construction
         of this value follows the same guidelines of Section 8.1.1.7.
         This implies that the proxy will compute its own branch
         parameter, which will be globally unique for that branch, and
         contain the requisite magic cookie. Note that this implies that
         the branch parameter will be different for different instances
         of a spiraled or looped request through a proxy.

         Proxies choosing to detect loops have an additional constraint
         in the value they use for construction of the branch parameter.
         A proxy choosing to detect loops SHOULD create a branch
         parameter separable into two parts by the implementation.  The
         first part MUST satisfy the constraints of Section 8.1.1.7 as
         described above.  The second is used to perform loop detection
         and distinguish loops from spirals.

         Loop detection is performed by verifying that, when a request
         returns to a proxy, those fields having an impact on the
         processing of the request have not changed.  The value placed
         in this part of the branch parameter SHOULD reflect all of
         those fields (including any Route, Proxy-Require and Proxy-
         Authorization header fields).  This is to ensure that if the
         request is routed back to the proxy and one of those fields
         changes, it is treated as a spiral and not a loop (see Section
         16.3).  A common way to create this value is to compute a
         cryptographic hash of the To tag, From tag, Call-ID header
         field, the Request-URI of the request received (before
         translation), the topmost Via header, and the sequence number
         from the CSeq header field, in addition to any Proxy-Require
         and Proxy-Authorization header fields that may be present.  The


         algorithm used to compute the hash is implementation-dependent,
         but MD5 (RFC 1321 [35]), expressed in hexadecimal, is a
         reasonable choice.  (Base64 is not permissible for a token.)

         If a proxy wishes to detect loops, the "branch" parameter it
         supplies MUST depend on all information affecting processing of
         a request, including the incoming Request-URI and any header
         fields affecting the request's admission or routing.  This is
         necessary to distinguish looped requests from requests whose
         routing parameters have changed before returning to this
         server.

         The request method MUST NOT be included in the calculation of
         the branch parameter.  In particular, CANCEL and ACK requests
         (for non-2xx responses) MUST have the same branch value as the
         corresponding request they cancel or acknowledge.  The branch
         parameter is used in correlating those requests at the server
         handling them (see Sections 17.2.3 and 9.2).

      9. Add a Content-Length header field if necessary

         If the request will be sent to the next hop using a stream-
         based transport and the copy contains no Content-Length header
         field, the proxy MUST insert one with the correct value for the
         body of the request (see Section 20.14).

      10. Forward Request

         A stateful proxy MUST create a new client transaction for this
         request as described in Section 17.1 and instructs the
         transaction to send the request using the address, port and
         transport determined in step 7.

      11. Set timer C

         In order to handle the case where an INVITE request never
         generates a final response, the TU uses a timer which is called
         timer C.  Timer C MUST be set for each client transaction when
         an INVITE request is proxied.  The timer MUST be larger than 3
         minutes.  Section 16.7 bullet 2 discusses how this timer is
         updated with provisional responses, and Section 16.8 discusses
         processing when it fires.






16.7 Response Processing

   When a response is received by an element, it first tries to locate a
   client transaction (Section 17.1.3) matching the response.  If none
   is found, the element MUST process the response (even if it is an
   informational response) as a stateless proxy (described below).  If a
   match is found, the response is handed to the client transaction.

      Forwarding responses for which a client transaction (or more
      generally any knowledge of having sent an associated request) is
      not found improves robustness.  In particular, it ensures that
      "late" 2xx responses to INVITE requests are forwarded properly.

   As client transactions pass responses to the proxy layer, the
   following processing MUST take place:

      1.  Find the appropriate response context

      2.  Update timer C for provisional responses

      3.  Remove the topmost Via

      4.  Add the response to the response context

      5.  Check to see if this response should be forwarded immediately

      6.  When necessary, choose the best final response from the
          response context

   If no final response has been forwarded after every client
   transaction associated with the response context has been terminated,
   the proxy must choose and forward the "best" response from those it
   has seen so far.

   The following processing MUST be performed on each response that is
   forwarded.  It is likely that more than one response to each request
   will be forwarded: at least each provisional and one final response.

      7.  Aggregate authorization header field values if necessary

      8.  Optionally rewrite Record-Route header field values

      9.  Forward the response

      10. Generate any necessary CANCEL requests



   Each of the above steps are detailed below:

      1.  Find Context

         The proxy locates the "response context" it created before
         forwarding the original request using the key described in
         Section 16.6.  The remaining processing steps take place in
         this context.

      2.  Update timer C for provisional responses

         For an INVITE transaction, if the response is a provisional
         response with status codes 101 to 199 inclusive (i.e., anything
         but 100), the proxy MUST reset timer C for that client
         transaction.  The timer MAY be reset to a different value, but
         this value MUST be greater than 3 minutes.

      3.  Via

         The proxy removes the topmost Via header field value from the
         response.

         If no Via header field values remain in the response, the
         response was meant for this element and MUST NOT be forwarded.
         The remainder of the processing described in this section is
         not performed on this message, the UAC processing rules
         described in Section 8.1.3 are followed instead (transport
         layer processing has already occurred).

         This will happen, for instance, when the element generates
         CANCEL requests as described in Section 10.

      4.  Add response to context

         Final responses received are stored in the response context
         until a final response is generated on the server transaction
         associated with this context.  The response may be a candidate
         for the best final response to be returned on that server
         transaction.  Information from this response may be needed in
         forming the best response, even if this response is not chosen.

         If the proxy chooses to recurse on any contacts in a 3xx
         response by adding them to the target set, it MUST remove them
         from the response before adding the response to the response
         context.  However, a proxy SHOULD NOT recurse to a non-SIPS URI
         if the Request-URI of the original request was a SIPS URI.  If


         the proxy recurses on all of the contacts in a 3xx response,
         the proxy SHOULD NOT add the resulting contactless response to
         the response context.

         Removing the contact before adding the response to the response
         context prevents the next element upstream from retrying a
         location this proxy has already attempted.

         3xx responses may contain a mixture of SIP, SIPS, and non-SIP
         URIs.  A proxy may choose to recurse on the SIP and SIPS URIs
         and place the remainder into the response context to be
         returned, potentially in the final response.

         If a proxy receives a 416 (Unsupported URI Scheme) response to
         a request whose Request-URI scheme was not SIP, but the scheme
         in the original received request was SIP or SIPS (that is, the
         proxy changed the scheme from SIP or SIPS to something else
         when it proxied a request), the proxy SHOULD add a new URI to
         the target set.  This URI SHOULD be a SIP URI version of the
         non-SIP URI that was just tried.  In the case of the tel URL,
         this is accomplished by placing the telephone-subscriber part
         of the tel URL into the user part of the SIP URI, and setting
         the hostpart to the domain where the prior request was sent.
         See Section 19.1.6 for more detail on forming SIP URIs from tel
         URLs.

         As with a 3xx response, if a proxy "recurses" on the 416 by
         trying a SIP or SIPS URI instead, the 416 response SHOULD NOT
         be added to the response context.

      5.  Check response for forwarding

         Until a final response has been sent on the server transaction,
         the following responses MUST be forwarded immediately:

         -  Any provisional response other than 100 (Trying)

         -  Any 2xx response

         If a 6xx response is received, it is not immediately forwarded,
         but the stateful proxy SHOULD cancel all client pending
         transactions as described in Section 10, and it MUST NOT create
         any new branches in this context.

         This is a change from RFC 2543, which mandated that the proxy
         was to forward the 6xx response immediately.  For an INVITE
         transaction, this approach had the problem that a 2xx response
         could arrive on another branch, in which case the proxy would
         have to forward the 2xx.  The result was that the UAC could
         receive a 6xx response followed by a 2xx response, which should
         never be allowed to happen.  Under the new rules, upon
         receiving a 6xx, a proxy will issue a CANCEL request, which
         will generally result in 487 responses from all outstanding
         client transactions, and then at that point the 6xx is
         forwarded upstream.

         After a final response has been sent on the server transaction,
         the following responses MUST be forwarded immediately:

         -  Any 2xx response to an INVITE request

         A stateful proxy MUST NOT immediately forward any other
         responses.  In particular, a stateful proxy MUST NOT forward
         any 100 (Trying) response.  Those responses that are candidates
         for forwarding later as the "best" response have been gathered
         as described in step "Add Response to Context".

         Any response chosen for immediate forwarding MUST be processed
         as described in steps "Aggregate Authorization Header Field
         Values" through "Record-Route".

         This step, combined with the next, ensures that a stateful
         proxy will forward exactly one final response to a non-INVITE
         request, and either exactly one non-2xx response or one or more
         2xx responses to an INVITE request.

      6.  Choosing the best response

         A stateful proxy MUST send a final response to a response
         context's server transaction if no final responses have been
         immediately forwarded by the above rules and all client
         transactions in this response context have been terminated.

         The stateful proxy MUST choose the "best" final response among
         those received and stored in the response context.

         If there are no final responses in the context, the proxy MUST
         send a 408 (Request Timeout) response to the server
         transaction.

         Otherwise, the proxy MUST forward a response from the responses
         stored in the response context.  It MUST choose from the 6xx
         class responses if any exist in the context.  If no 6xx class
         responses are present, the proxy SHOULD choose from the lowest
         response class stored in the response context.  The proxy MAY
         select any response within that chosen class.  The proxy SHOULD
         give preference to responses that provide information affecting
         resubmission of this request, such as 401, 407, 415, 420, and
         484 if the 4xx class is chosen.

         A proxy which receives a 503 (Service Unavailable) response
         SHOULD NOT forward it upstream unless it can determine that any
         subsequent requests it might proxy will also generate a 503.
         In other words, forwarding a 503 means that the proxy knows it
         cannot service any requests, not just the one for the Request-
         URI in the request which generated the 503.  If the only
         response that was received is a 503, the proxy SHOULD generate
         a 500 response and forward that upstream.

         The forwarded response MUST be processed as described in steps
         "Aggregate Authorization Header Field Values" through "Record-
         Route".

         For example, if a proxy forwarded a request to 4 locations, and
         received 503, 407, 501, and 404 responses, it may choose to
         forward the 407 (Proxy Authentication Required) response.

         1xx and 2xx responses may be involved in the establishment of
         dialogs.  When a request does not contain a To tag, the To tag
         in the response is used by the UAC to distinguish multiple
         responses to a dialog creating request.  A proxy MUST NOT
         insert a tag into the To header field of a 1xx or 2xx response
         if the request did not contain one.  A proxy MUST NOT modify
         the tag in the To header field of a 1xx or 2xx response.

         Since a proxy may not insert a tag into the To header field of
         a 1xx response to a request that did not contain one, it cannot
         issue non-100 provisional responses on its own.  However, it
         can branch the request to a UAS sharing the same element as the
         proxy.  This UAS can return its own provisional responses,
         entering into an early dialog with the initiator of the
         request.  The UAS does not have to be a discreet process from
         the proxy.  It could be a virtual UAS implemented in the same
         code space as the proxy.

         3-6xx responses are delivered hop-by-hop.  When issuing a 3-6xx
         response, the element is effectively acting as a UAS, issuing
         its own response, usually based on the responses received from
         downstream elements.  An element SHOULD preserve the To tag
         when simply forwarding a 3-6xx response to a request that did
         not contain a To tag.

         A proxy MUST NOT modify the To tag in any forwarded response to
         a request that contains a To tag.
         While it makes no difference to the upstream elements if the
         proxy replaced the To tag in a forwarded 3-6xx response,
         preserving the original tag may assist with debugging.

         When the proxy is aggregating information from several
         responses, choosing a To tag from among them is arbitrary, and
         generating a new To tag may make debugging easier.  This
         happens, for instance, when combining 401 (Unauthorized) and
         407 (Proxy Authentication Required) challenges, or combining
         Contact values from unencrypted and unauthenticated 3xx
         responses.

      7.  Aggregate Authorization Header Field Values

         If the selected response is a 401 (Unauthorized) or 407 (Proxy
         Authentication Required), the proxy MUST collect any WWW-
         Authenticate and Proxy-Authenticate header field values from
         all other 401 (Unauthorized) and 407 (Proxy Authentication
         Required) responses received so far in this response context
         and add them to this response without modification before
         forwarding.  The resulting 401 (Unauthorized) or 407 (Proxy
         Authentication Required) response could have several WWW-
         Authenticate AND Proxy-Authenticate header field values.

         This is necessary because any or all of the destinations the
         request was forwarded to may have requested credentials.  The
         client needs to receive all of those challenges and supply
         credentials for each of them when it retries the request.
         Motivation for this behavior is provided in Section 26.

      8.  Record-Route

         If the selected response contains a Record-Route header field
         value originally provided by this proxy, the proxy MAY choose
         to rewrite the value before forwarding the response.  This
         allows the proxy to provide different URIs for itself to the
         next upstream and downstream elements.  A proxy may choose to
         use this mechanism for any reason.  For instance, it is useful
         for multi-homed hosts.

         If the proxy received the request over TLS, and sent it out
         over a non-TLS connection, the proxy MUST rewrite the URI in
         the Record-Route header field to be a SIPS URI.  If the proxy
         received the request over a non-TLS connection, and sent it out
         over TLS, the proxy MUST rewrite the URI in the Record-Route
         header field to be a SIP URI.


         The new URI provided by the proxy MUST satisfy the same
         constraints on URIs placed in Record-Route header fields in
         requests (see Step 4 of Section 16.6) with the following
         modifications:

         The URI SHOULD NOT contain the transport parameter unless the
         proxy has knowledge that the next upstream (as opposed to
         downstream) element that will be in the path of subsequent
         requests supports that transport.

         When a proxy does decide to modify the Record-Route header
         field in the response, one of the operations it performs is
         locating the Record-Route value that it had inserted.  If the
         request spiraled, and the proxy inserted a Record-Route value
         in each iteration of the spiral, locating the correct value in
         the response (which must be the proper iteration in the reverse
         direction) is tricky.  The rules above recommend that a proxy
         wishing to rewrite Record-Route header field values insert
         sufficiently distinct URIs into the Record-Route header field
         so that the right one may be selected for rewriting.  A
         RECOMMENDED mechanism to achieve this is for the proxy to
         append a unique identifier for the proxy instance to the user
         portion of the URI.

         When the response arrives, the proxy modifies the first
         Record-Route whose identifier matches the proxy instance.  The
         modification results in a URI without this piece of data
         appended to the user portion of the URI.  Upon the next
         iteration, the same algorithm (find the topmost Record-Route
         header field value with the parameter) will correctly extract
         the next Record-Route header field value inserted by that
         proxy.

         Not every response to a request to which a proxy adds a
         Record-Route header field value will contain a Record-Route
         header field.  If the response does contain a Record-Route
         header field, it will contain the value the proxy added.

      9.  Forward response

         After performing the processing described in steps "Aggregate
         Authorization Header Field Values" through "Record-Route", the
         proxy MAY perform any feature specific manipulations on the
         selected response.  The proxy MUST NOT add to, modify, or
         remove the message body.  Unless otherwise specified, the proxy
         MUST NOT remove any header field values other than the Via
         header field value discussed in Section 16.7 Item 3.  In
         particular, the proxy MUST NOT remove any "received" parameter
         it may have added to the next Via header field value while
         processing the request associated with this response.  The
         proxy MUST pass the response to the server transaction
         associated with the response context.  This will result in the
         response being sent to the location now indicated in the
         topmost Via header field value.  If the server transaction is
         no longer available to handle the transmission, the element
         MUST forward the response statelessly by sending it to the
         server transport.  The server transaction might indicate
         failure to send the response or signal a timeout in its state
         machine.  These errors would be logged for diagnostic purposes
         as appropriate, but the protocol requires no remedial action
         from the proxy.

         The proxy MUST maintain the response context until all of its
         associated transactions have been terminated, even after
         forwarding a final response.

      10. Generate CANCELs

         If the forwarded response was a final response, the proxy MUST
         generate a CANCEL request for all pending client transactions
         associated with this response context.  A proxy SHOULD also
         generate a CANCEL request for all pending client transactions
         associated with this response context when it receives a 6xx
         response.  A pending client transaction is one that has
         received a provisional response, but no final response (it is
         in the proceeding state) and has not had an associated CANCEL
         generated for it.  Generating CANCEL requests is described in
         Section 9.1.

         The requirement to CANCEL pending client transactions upon
         forwarding a final response does not guarantee that an endpoint
         will not receive multiple 200 (OK) responses to an INVITE.  200
         (OK) responses on more than one branch may be generated before
         the CANCEL requests can be sent and processed.  Further, it is
         reasonable to expect that a future extension may override this
         requirement to issue CANCEL requests.

16.8 Processing Timer C

   If timer C should fire, the proxy MUST either reset the timer with
   any value it chooses, or terminate the client transaction.  If the
   client transaction has received a provisional response, the proxy
   MUST generate a CANCEL request matching that transaction.  If the
   client transaction has not received a provisional response, the proxy
   MUST behave as if the transaction received a 408 (Request Timeout)
   response.
   Allowing the proxy to reset the timer allows the proxy to dynamically
   extend the transaction's lifetime based on current conditions (such
   as utilization) when the timer fires.

16.9 Handling Transport Errors

   If the transport layer notifies a proxy of an error when it tries to
   forward a request (see Section 18.4), the proxy MUST behave as if the
   forwarded request received a 503 (Service Unavailable) response.

   If the proxy is notified of an error when forwarding a response, it
   drops the response.  The proxy SHOULD NOT cancel any outstanding
   client transactions associated with this response context due to this
   notification.

      If a proxy cancels its outstanding client transactions, a single
      malicious or misbehaving client can cause all transactions to fail
      through its Via header field.

16.10 CANCEL Processing

   A stateful proxy MAY generate a CANCEL to any other request it has
   generated at any time (subject to receiving a provisional response to
   that request as described in section 9.1).  A proxy MUST cancel any
   pending client transactions associated with a response context when
   it receives a matching CANCEL request.

   A stateful proxy MAY generate CANCEL requests for pending INVITE
   client transactions based on the period specified in the INVITE's
   Expires header field elapsing.  However, this is generally
   unnecessary since the endpoints involved will take care of signaling
   the end of the transaction.

   While a CANCEL request is handled in a stateful proxy by its own
   server transaction, a new response context is not created for it.
   Instead, the proxy layer searches its existing response contexts for
   the server transaction handling the request associated with this
   CANCEL.  If a matching response context is found, the element MUST
   immediately return a 200 (OK) response to the CANCEL request.  In
   this case, the element is acting as a user agent server as defined in
   Section 8.2.  Furthermore, the element MUST generate CANCEL requests
   for all pending client transactions in the context as described in
   Section 16.7 step 10.

   If a response context is not found, the element does not have any
   knowledge of the request to apply the CANCEL to.  It MUST statelessly
   forward the CANCEL request (it may have statelessly forwarded the
   associated request previously).
16.11 Stateless Proxy

   When acting statelessly, a proxy is a simple message forwarder.  Much
   of the processing performed when acting statelessly is the same as
   when behaving statefully.  The differences are detailed here.

   A stateless proxy does not have any notion of a transaction, or of
   the response context used to describe stateful proxy behavior.
   Instead, the stateless proxy takes messages, both requests and
   responses, directly from the transport layer (See section 18).  As a
   result, stateless proxies do not retransmit messages on their own.
   They do, however, forward all retransmissions they receive (they do
   not have the ability to distinguish a retransmission from the
   original message).  Furthermore, when handling a request statelessly,
   an element MUST NOT generate its own 100 (Trying) or any other
   provisional response.

   A stateless proxy MUST validate a request as described in Section
   16.3

   A stateless proxy MUST follow the request processing steps described
   in Sections 16.4 through 16.5 with the following exception:

      o  A stateless proxy MUST choose one and only one target from the
         target set.  This choice MUST only rely on fields in the
         message and time-invariant properties of the server.  In
         particular, a retransmitted request MUST be forwarded to the
         same destination each time it is processed.  Furthermore,
         CANCEL and non-Routed ACK requests MUST generate the same
         choice as their associated INVITE.

   A stateless proxy MUST follow the request processing steps described
   in Section 16.6 with the following exceptions:

      o  The requirement for unique branch IDs across space and time
         applies to stateless proxies as well.  However, a stateless
         proxy cannot simply use a random number generator to compute
         the first component of the branch ID, as described in Section
         16.6 bullet 8.  This is because retransmissions of a request
         need to have the same value, and a stateless proxy cannot tell
         a retransmission from the original request.  Therefore, the
         component of the branch parameter that makes it unique MUST be
         the same each time a retransmitted request is forwarded.  Thus
         for a stateless proxy, the branch parameter MUST be computed as
         a combinatoric function of message parameters which are
         invariant on retransmission.


         The stateless proxy MAY use any technique it likes to guarantee
         uniqueness of its branch IDs across transactions.  However, the
         following procedure is RECOMMENDED.  The proxy examines the
         branch ID in the topmost Via header field of the received
         request.  If it begins with the magic cookie, the first
         component of the branch ID of the outgoing request is computed
         as a hash of the received branch ID.  Otherwise, the first
         component of the branch ID is computed as a hash of the topmost
         Via, the tag in the To header field, the tag in the From header
         field, the Call-ID header field, the CSeq number (but not
         method), and the Request-URI from the received request.  One of
         these fields will always vary across two different
         transactions.

      o  All other message transformations specified in Section 16.6
         MUST result in the same transformation of a retransmitted
         request.  In particular, if the proxy inserts a Record-Route
         value or pushes URIs into the Route header field, it MUST place
         the same values in retransmissions of the request.  As for the
         Via branch parameter, this implies that the transformations
         MUST be based on time-invariant configuration or
         retransmission-invariant properties of the request.

      o  A stateless proxy determines where to forward the request as
         described for stateful proxies in Section 16.6 Item 10.  The
         request is sent directly to the transport layer instead of
         through a client transaction.

         Since a stateless proxy must forward retransmitted requests to
         the same destination and add identical branch parameters to
         each of them, it can only use information from the message
         itself and time-invariant configuration data for those
         calculations.  If the configuration state is not time-invariant
         (for example, if a routing table is updated) any requests that
         could be affected by the change may not be forwarded
         statelessly during an interval equal to the transaction timeout
         window before or after the change.  The method of processing
         the affected requests in that interval is an implementation
         decision.  A common solution is to forward them transaction
         statefully.

   Stateless proxies MUST NOT perform special processing for CANCEL
   requests.  They are processed by the above rules as any other
   requests.  In particular, a stateless proxy applies the same Route
   header field processing to CANCEL requests that it applies to any
   other request.


   Response processing as described in Section 16.7 does not apply to a
   proxy behaving statelessly.  When a response arrives at a stateless
   proxy, the proxy MUST inspect the sent-by value in the first
   (topmost) Via header field value.  If that address matches the proxy,
   (it equals a value this proxy has inserted into previous requests)
   the proxy MUST remove that header field value from the response and
   forward the result to the location indicated in the next Via header
   field value.  The proxy MUST NOT add to, modify, or remove the
   message body.  Unless specified otherwise, the proxy MUST NOT remove
   any other header field values.  If the address does not match the
   proxy, the message MUST be silently discarded.

16.12 Summary of Proxy Route Processing

   In the absence of local policy to the contrary, the processing a
   proxy performs on a request containing a Route header field can be
   summarized in the following steps.

      1.  The proxy will inspect the Request-URI.  If it indicates a
          resource owned by this proxy, the proxy will replace it with
          the results of running a location service.  Otherwise, the
          proxy will not change the Request-URI.

      2.  The proxy will inspect the URI in the topmost Route header
          field value.  If it indicates this proxy, the proxy removes it
          from the Route header field (this route node has been
          reached).

      3.  The proxy will forward the request to the resource indicated
          by the URI in the topmost Route header field value or in the
          Request-URI if no Route header field is present.  The proxy
          determines the address, port and transport to use when
          forwarding the request by applying the procedures in [4] to
          that URI.

   If no strict-routing elements are encountered on the path of the
   request, the Request-URI will always indicate the target of the
   request.

16.12.1 Examples

16.12.1.1 Basic SIP Trapezoid

   This scenario is the basic SIP trapezoid, U1 -&amp;gt; P1 -&amp;gt; P2 -&amp;gt; U2, with
   both proxies record-routing.  Here is the flow.



   U1 sends:

      INVITE sip:callee@domain.com SIP/2.0
      Contact: sip:caller@u1.example.com

   to P1.  P1 is an outbound proxy.  P1 is not responsible for
   domain.com, so it looks it up in DNS and sends it there.  It also
   adds a Record-Route header field value:

      INVITE sip:callee@domain.com SIP/2.0
      Contact: sip:caller@u1.example.com
      Record-Route: &amp;lt;sip:p1.example.com;lr&amp;gt;

   P2 gets this.  It is responsible for domain.com so it runs a location
   service and rewrites the Request-URI.  It also adds a Record-Route
   header field value.  There is no Route header field, so it resolves
   the new Request-URI to determine where to send the request:

      INVITE sip:callee@u2.domain.com SIP/2.0
      Contact: sip:caller@u1.example.com
      Record-Route: &amp;lt;sip:p2.domain.com;lr&amp;gt;
      Record-Route: &amp;lt;sip:p1.example.com;lr&amp;gt;

   The callee at u2.domain.com gets this and responds with a 200 OK:

      SIP/2.0 200 OK
      Contact: sip:callee@u2.domain.com
      Record-Route: &amp;lt;sip:p2.domain.com;lr&amp;gt;
      Record-Route: &amp;lt;sip:p1.example.com;lr&amp;gt;

   The callee at u2 also sets its dialog state's remote target URI to
   sip:caller@u1.example.com and its route set to:

      (&amp;lt;sip:p2.domain.com;lr&amp;gt;,&amp;lt;sip:p1.example.com;lr&amp;gt;)

   This is forwarded by P2 to P1 to U1 as normal.  Now, U1 sets its
   dialog state's remote target URI to sip:callee@u2.domain.com and its
   route set to:

      (&amp;lt;sip:p1.example.com;lr&amp;gt;,&amp;lt;sip:p2.domain.com;lr&amp;gt;)

   Since all the route set elements contain the lr parameter, U1
   constructs the following BYE request:

      BYE sip:callee@u2.domain.com SIP/2.0
      Route: &amp;lt;sip:p1.example.com;lr&amp;gt;,&amp;lt;sip:p2.domain.com;lr&amp;gt;


   As any other element (including proxies) would do, it resolves the
   URI in the topmost Route header field value using DNS to determine
   where to send the request.  This goes to P1.  P1 notices that it is
   not responsible for the resource indicated in the Request-URI so it
   doesn't change it.  It does see that it is the first value in the
   Route header field, so it removes that value, and forwards the
   request to P2:

      BYE sip:callee@u2.domain.com SIP/2.0
      Route: &amp;lt;sip:p2.domain.com;lr&amp;gt;

   P2 also notices it is not responsible for the resource indicated by
   the Request-URI (it is responsible for domain.com, not
   u2.domain.com), so it doesn't change it.  It does see itself in the
   first Route header field value, so it removes it and forwards the
   following to u2.domain.com based on a DNS lookup against the
   Request-URI:

      BYE sip:callee@u2.domain.com SIP/2.0

16.12.1.2 Traversing a Strict-Routing Proxy

   In this scenario, a dialog is established across four proxies, each
   of which adds Record-Route header field values.  The third proxy
   implements the strict-routing procedures specified in RFC 2543 and
   many works in progress.

      U1-&amp;gt;P1-&amp;gt;P2-&amp;gt;P3-&amp;gt;P4-&amp;gt;U2

   The INVITE arriving at U2 contains:

      INVITE sip:callee@u2.domain.com SIP/2.0
      Contact: sip:caller@u1.example.com
      Record-Route: &amp;lt;sip:p4.domain.com;lr&amp;gt;
      Record-Route: &amp;lt;sip:p3.middle.com&amp;gt;
      Record-Route: &amp;lt;sip:p2.example.com;lr&amp;gt;
      Record-Route: &amp;lt;sip:p1.example.com;lr&amp;gt;

   Which U2 responds to with a 200 OK.  Later, U2 sends the following
   BYE request to P4 based on the first Route header field value.

      BYE sip:caller@u1.example.com SIP/2.0
      Route: &amp;lt;sip:p4.domain.com;lr&amp;gt;
      Route: &amp;lt;sip:p3.middle.com&amp;gt;
      Route: &amp;lt;sip:p2.example.com;lr&amp;gt;
      Route: &amp;lt;sip:p1.example.com;lr&amp;gt;


   P4 is not responsible for the resource indicated in the Request-URI
   so it will leave it alone.  It notices that it is the element in the
   first Route header field value so it removes it.  It then prepares to
   send the request based on the now first Route header field value of
   sip:p3.middle.com, but it notices that this URI does not contain the
   lr parameter, so before sending, it reformats the request to be:

      BYE sip:p3.middle.com SIP/2.0
      Route: &amp;lt;sip:p2.example.com;lr&amp;gt;
      Route: &amp;lt;sip:p1.example.com;lr&amp;gt;
      Route: &amp;lt;sip:caller@u1.example.com&amp;gt;

   P3 is a strict router, so it forwards the following to P2:

      BYE sip:p2.example.com;lr SIP/2.0
      Route: &amp;lt;sip:p1.example.com;lr&amp;gt;
      Route: &amp;lt;sip:caller@u1.example.com&amp;gt;

   P2 sees the request-URI is a value it placed into a Record-Route
   header field, so before further processing, it rewrites the request
   to be:

      BYE sip:caller@u1.example.com SIP/2.0
      Route: &amp;lt;sip:p1.example.com;lr&amp;gt;

   P2 is not responsible for u1.example.com, so it sends the request to
   P1 based on the resolution of the Route header field value.

   P1 notices itself in the topmost Route header field value, so it
   removes it, resulting in:

      BYE sip:caller@u1.example.com SIP/2.0

   Since P1 is not responsible for u1.example.com and there is no Route
   header field, P1 will forward the request to u1.example.com based on
   the Request-URI.

16.12.1.3 Rewriting Record-Route Header Field Values

   In this scenario, U1 and U2 are in different private namespaces and
   they enter a dialog through a proxy P1, which acts as a gateway
   between the namespaces.

      U1-&amp;gt;P1-&amp;gt;U2




   U1 sends:

      INVITE sip:callee@gateway.leftprivatespace.com SIP/2.0
      Contact: &amp;lt;sip:caller@u1.leftprivatespace.com&amp;gt;

   P1 uses its location service and sends the following to U2:

      INVITE sip:callee@rightprivatespace.com SIP/2.0
      Contact: &amp;lt;sip:caller@u1.leftprivatespace.com&amp;gt;
      Record-Route: &amp;lt;sip:gateway.rightprivatespace.com;lr&amp;gt;

   U2 sends this 200 (OK) back to P1:

      SIP/2.0 200 OK
      Contact: &amp;lt;sip:callee@u2.rightprivatespace.com&amp;gt;
      Record-Route: &amp;lt;sip:gateway.rightprivatespace.com;lr&amp;gt;

   P1 rewrites its Record-Route header parameter to provide a value that
   U1 will find useful, and sends the following to U1:

      SIP/2.0 200 OK
      Contact: &amp;lt;sip:callee@u2.rightprivatespace.com&amp;gt;
      Record-Route: &amp;lt;sip:gateway.leftprivatespace.com;lr&amp;gt;

   Later, U1 sends the following BYE request to P1:

      BYE sip:callee@u2.rightprivatespace.com SIP/2.0
      Route: &amp;lt;sip:gateway.leftprivatespace.com;lr&amp;gt;

   which P1 forwards to U2 as:

      BYE sip:callee@u2.rightprivatespace.com SIP/2.0

17 Transactions

   SIP is a transactional protocol: interactions between components take
   place in a series of independent message exchanges.  Specifically, a
   SIP transaction consists of a single request and any responses to
   that request, which include zero or more provisional responses and
   one or more final responses.  In the case of a transaction where the
   request was an INVITE (known as an INVITE transaction), the
   transaction also includes the ACK only if the final response was not
   a 2xx response.  If the response was a 2xx, the ACK is not considered
   part of the transaction.

      The reason for this separation is rooted in the importance of
      delivering all 200 (OK) responses to an INVITE to the UAC.  To
      deliver them all to the UAC, the UAS alone takes responsibility
      for retransmitting them (see Section 13.3.1.4), and the UAC alone
      takes responsibility for acknowledging them with ACK (see Section
      13.2.2.4).  Since this ACK is retransmitted only by the UAC, it is
      effectively considered its own transaction.

   Transactions have a client side and a server side.  The client side
   is known as a client transaction and the server side as a server
   transaction.  The client transaction sends the request, and the
   server transaction sends the response.  The client and server
   transactions are logical functions that are embedded in any number of
   elements.  Specifically, they exist within user agents and stateful
   proxy servers.  Consider the example in Section 4.  In this example,
   the UAC executes the client transaction, and its outbound proxy
   executes the server transaction.  The outbound proxy also executes a
   client transaction, which sends the request to a server transaction
   in the inbound proxy.  That proxy also executes a client transaction,
   which in turn sends the request to a server transaction in the UAS.
   This is shown in Figure 4.

   +---------+        +---------+        +---------+        +---------+
   |      +-+|Request |+-+   +-+|Request |+-+   +-+|Request |+-+      |
   |      |C||-------&amp;gt;||S|   |C||-------&amp;gt;||S|   |C||-------&amp;gt;||S|      |
   |      |l||        ||e|   |l||        ||e|   |l||        ||e|      |
   |      |i||        ||r|   |i||        ||r|   |i||        ||r|      |
   |      |e||        ||v|   |e||        ||v|   |e||        ||v|      |
   |      |n||        ||e|   |n||        ||e|   |n||        ||e|      |
   |      |t||        ||r|   |t||        ||r|   |t||        ||r|      |
   |      | ||        || |   | ||        || |   | ||        || |      |
   |      |T||        ||T|   |T||        ||T|   |T||        ||T|      |
   |      |r||        ||r|   |r||        ||r|   |r||        ||r|      |
   |      |a||        ||a|   |a||        ||a|   |a||        ||a|      |
   |      |n||        ||n|   |n||        ||n|   |n||        ||n|      |
   |      |s||Response||s|   |s||Response||s|   |s||Response||s|      |
   |      +-+|&amp;lt;-------|+-+   +-+|&amp;lt;-------|+-+   +-+|&amp;lt;-------|+-+      |
   +---------+        +---------+        +---------+        +---------+
      UAC               Outbound           Inbound              UAS
                        Proxy               Proxy

                  Figure 4: Transaction relationships

   A stateless proxy does not contain a client or server transaction.
   The transaction exists between the UA or stateful proxy on one side,
   and the UA or stateful proxy on the other side.  As far as SIP
   transactions are concerned, stateless proxies are effectively
   transparent.  The purpose of the client transaction is to receive a
   request from the element in which the client is embedded (call this
   element the "Transaction User" or TU; it can be a UA or a stateful
   proxy), and reliably deliver the request to a server transaction.
   The client transaction is also responsible for receiving responses
   and delivering them to the TU, filtering out any response
   retransmissions or disallowed responses (such as a response to ACK).
   Additionally, in the case of an INVITE request, the client
   transaction is responsible for generating the ACK request for any
   final response accepting a 2xx response.

   Similarly, the purpose of the server transaction is to receive
   requests from the transport layer and deliver them to the TU.  The
   server transaction filters any request retransmissions from the
   network.  The server transaction accepts responses from the TU and
   delivers them to the transport layer for transmission over the
   network.  In the case of an INVITE transaction, it absorbs the ACK
   request for any final response excepting a 2xx response.

   The 2xx response and its ACK receive special treatment.  This
   response is retransmitted only by a UAS, and its ACK generated only
   by the UAC.  This end-to-end treatment is needed so that a caller
   knows the entire set of users that have accepted the call.  Because
   of this special handling, retransmissions of the 2xx response are
   handled by the UA core, not the transaction layer.  Similarly,
   generation of the ACK for the 2xx is handled by the UA core.  Each
   proxy along the path merely forwards each 2xx response to INVITE and
   its corresponding ACK.</pre></DIV><PRE>
<span class="p_word">class</span> Proxy(UserAgent):
    <span class="p_triple">'''Extends UserAgent to represents a stateless and stateful proxy. The base object represents original UAS.'''</span>
    <span class="p_word">def</span> __init__(self, stack, request=<span class="p_word">None</span>, server=<span class="p_word">None</span>):
        <span class="p_triple">'''Construct as Proxy UAS for the incoming request.'''</span>
        <span class="p_word">if</span> request <span class="p_word">is</span> <span class="p_word">None</span>: <span class="p_word">raise</span> ValueError(<span class="p_string">'Cannot create Proxy without incoming request'</span>)
        UserAgent.__init__(self, stack, request, server)
        self.branches = [] <span class="p_commentline"># all the client branches containing Transaction objects</span>

    <span class="p_word">def</span> createTransaction(self, request):
        <span class="p_triple">'''Delay the creation of transaction when sendResponse or sendRequest is invoked.'''</span>
        self.receivedRequest(<span class="p_word">None</span>, request) <span class="p_commentline"># don't create a transaction, but just invoke the callback</span>
        <span class="p_word">return</span> <span class="p_word">None</span>
    
    <span class="p_word">def</span> receivedRequest(self, transaction, request):
        <span class="p_triple">'''New incoming request. Transaction may be empty at this point.'''</span>
        <span class="p_word">if</span> transaction <span class="p_word">and</span> self.transaction <span class="p_word">and</span> transaction != self.transaction <span class="p_word">and</span> request.method != <span class="p_string">'CANCEL'</span>:
            <span class="p_word">raise</span> ValueError, <span class="p_string">'Invalid transaction for received request'</span>
        self.server = True <span class="p_commentline"># this becomes a UAS</span>
        <span class="p_commentline"># 16.3 request validation</span>
        <span class="p_word">if</span> request.uri.scheme <span class="p_word">not</span> <span class="p_word">in</span> [<span class="p_string">'sip'</span>, <span class="p_string">'sips'</span>]:
            self.sendResponse(<span class="p_number">416</span>, <span class="p_string">'Unsupported URI scheme'</span>)
            <span class="p_word">return</span>
        <span class="p_word">if</span> request[<span class="p_string">'Max-Forwards'</span>] <span class="p_word">and</span> int(request.first(<span class="p_string">'Max-Forwards'</span>).value) &lt; <span class="p_number">0</span>:
            self.sendResponse(<span class="p_number">483</span>, <span class="p_string">'Too many hops'</span>)
            <span class="p_word">return</span>
        <span class="p_word">if</span> <span class="p_string">'tag'</span> <span class="p_word">not</span> <span class="p_word">in</span> request.To: <span class="p_commentline"># out of dialog request</span>
            <span class="p_word">if</span> self.stack.findOtherTransaction(request, transaction): <span class="p_commentline"># request merging?</span>
                self.sendResponse(<span class="p_number">482</span>, <span class="p_string">"Loop detected - found another transaction"</span>)
                <span class="p_word">return</span>
        <span class="p_word">if</span> request[<span class="p_string">'Proxy-Require'</span>]: <span class="p_commentline"># TODO let the application handle Require header</span>
            <span class="p_word">if</span> request.method != <span class="p_string">'CANCEL'</span> <span class="p_word">and</span> request.method != <span class="p_string">'ACK'</span>: 
                response = self.createResponse(<span class="p_number">420</span>, <span class="p_string">'Bad extension'</span>)
                response.Unsupported = Header(str(request[<span class="p_string">'Proxy-Require'</span>].value), <span class="p_string">'Unsupported'</span>)
                self.sendResponse(response)
                <span class="p_word">return</span>
        <span class="p_word">if</span> transaction: self.transaction = transaction <span class="p_commentline"># store it</span>
        
        <span class="p_word">if</span> request.method == <span class="p_string">'CANCEL'</span>: 
            original = self.stack.findTransaction(Transaction.createId(transaction.branch, <span class="p_string">'INVITE'</span>))
            <span class="p_word">if</span> original:
                <span class="p_word">if</span> original.state == <span class="p_string">'proceeding'</span> <span class="p_word">or</span> original.state == <span class="p_string">'trying'</span>:
                    original.sendResponse(original.createResponse(<span class="p_number">487</span>, <span class="p_string">'Request terminated'</span>))
                self.createResponse(<span class="p_number">200</span>, <span class="p_string">'OK'</span>) <span class="p_commentline"># CANCEL response</span>
            <span class="p_commentline"># TODO: the To tag must be same in the two responses</span>
        
        <span class="p_commentline"># 16.4 route information processing</span>
        <span class="p_word">if</span> <span class="p_word">not</span> request.uri.user <span class="p_word">and</span> self.isLocal(request.uri) <span class="p_word">and</span> <span class="p_string">'lr'</span> <span class="p_word">in</span> request.uri.param <span class="p_word">and</span> request.Route:
            lastRoute = request.all(<span class="p_string">'Route'</span>)[-<span class="p_number">1</span>]; request.delete(<span class="p_string">'Route'</span>, position=-<span class="p_number">1</span>)
            request.uri = lastRoute.value.uri
        <span class="p_commentline">#if 'maddr' in request.uri.param: TODO: handle this case</span>
        <span class="p_word">if</span> request.Route <span class="p_word">and</span> self.isLocal(request.first(<span class="p_string">'Route'</span>).value.uri):
            request.delete(<span class="p_string">'Route'</span>, position=<span class="p_number">0</span>) <span class="p_commentline"># delete first Route header</span>
            
        self.stack.receivedRequest(self, request)
    
    <span class="p_word">def</span> isLocal(self, uri):
        <span class="p_triple">'''Check whether the give uri represents local address (host:port) ?'''</span>
        <span class="p_word">return</span> self.stack.transport.host == uri.host <span class="p_word">and</span> self.stack.transport.port == uri.port
     
    <span class="p_word">def</span> sendResponse(self, response, responsetext=<span class="p_word">None</span>, content=<span class="p_word">None</span>, contentType=<span class="p_word">None</span>, createDialog=True):
        <span class="p_triple">'''Invoke the base class to send a response to original UAS. Create a transaction beforehand if needed.'''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> self.transaction: <span class="p_commentline"># create a transaction if doesn't exist</span>
            self.transaction = Transaction.createServer(self.stack, self, self.request, self.stack.transport, self.stack.tag, start=False)
        UserAgent.sendResponse(self, response, responsetext, content, contentType, False) <span class="p_commentline"># never create dialog</span>
    
    <span class="p_word">def</span> createRequest(self, method, dest, stateless=False, recordRoute=False, headers=[], route=[]):
        <span class="p_triple">'''Create a proxied request from the original request, using destination (host, port). Additional arguments
        modify how the proxied request is generated. The caller must invoke sendRequest to send the returned request.'''</span>
        <span class="p_word">if</span> method != self.request.method: <span class="p_word">raise</span> ValueError(<span class="p_string">'method in createRequest must be same as original UAS for proxy'</span>)
        request = self.request.dup() <span class="p_commentline"># so that original is not modified</span>
        <span class="p_word">if</span> <span class="p_word">not</span> stateless <span class="p_word">and</span> <span class="p_word">not</span> self.transaction: <span class="p_commentline"># need to create a transaction</span>
            self.transaction = Transaction.createServer(self.stack, self, self.request, self.stack.transport, self.stack.tag, start=False)
        <span class="p_word">if</span> isinstance(dest, Address): request.uri = dest.uri.dup()
        <span class="p_word">elif</span> isinstance(dest, tuple): request.uri = URI(request.uri.scheme + <span class="p_string">':'</span> + request.uri.user + <span class="p_string">'@'</span> + dest[<span class="p_number">0</span>] + <span class="p_string">':'</span> + str(dest[<span class="p_number">1</span>]))
        <span class="p_word">else</span>: request.uri = dest.dup() <span class="p_commentline"># so that original is not modified</span>
        
        request[<span class="p_string">'Max-Forwards'</span>] = Header(str(int(request.first(<span class="p_string">'Max-Forwards'</span>).value)-<span class="p_number">1</span>) <span class="p_word">if</span> request[<span class="p_string">'Max-Forwards'</span>] <span class="p_word">else</span> <span class="p_string">'70'</span>, <span class="p_string">'Max-Forwards'</span>)
        <span class="p_word">if</span> recordRoute:
            rr = Address(str(self.stack.uri))
            rr.uri.param[<span class="p_string">'lr'</span>] = <span class="p_word">None</span>
            rr.mustQuote = True
            <span class="p_commentline"># TODO: take care of sips URI</span>
            request.insert(Header(str(rr), <span class="p_string">'Record-Route'</span>))
        <span class="p_word">for</span> h <span class="p_word">in</span> headers: request.insert(h, append=True) <span class="p_commentline"># insert additional headers</span>
        <span class="p_word">for</span> h <span class="p_word">in</span> reversed(route): request.insert(h, append=False) <span class="p_commentline"># insert the routes</span>
        Via = self.stack.createVia(self.secure)
        Via.branch = Transaction.createBranch(request, False)
        request.insert(Via)
        <span class="p_word">return</span> request
        
    <span class="p_word">def</span> sendRequest(self, request):
        <span class="p_triple">'''Proxy a request in a new client transaction.'''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> request.Route: target = request.uri
        <span class="p_word">else</span>:
            routes = request.all(<span class="p_string">'Route'</span>)
            <span class="p_word">if</span> len(routes) &gt; <span class="p_number">0</span>:
                target = routes[<span class="p_number">0</span>].value.uri
                <span class="p_word">if</span> <span class="p_word">not</span> target <span class="p_word">or</span> <span class="p_string">'lr'</span> <span class="p_word">not</span> <span class="p_word">in</span> target.param: <span class="p_commentline"># strict route</span>
                    <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'strict route target='</span>, target, <span class="p_string">'routes='</span>, routes
                    <span class="p_word">del</span> routes[<span class="p_number">0</span>] <span class="p_commentline"># ignore first route</span>
                    <span class="p_word">if</span> len(routes) &gt; <span class="p_number">0</span>:
                        <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'appending our route'</span>
                        routes.append(Header(str(request.uri), <span class="p_string">'Route'</span>))
                    request.Route = routes
                    request.uri = target;
        
        self.stack.sending(self, request) 
        
        <span class="p_word">class</span> Branch(object): 
            __slots__ = (<span class="p_string">'request'</span>, <span class="p_string">'response'</span>, <span class="p_string">'remoteCandidates'</span>, <span class="p_string">'transaction'</span>, <span class="p_string">'cancelRequest'</span>)
            <span class="p_word">def</span> __init__(self): self.request = self.response = self.remoteCandidates = self.transaction = self.cancelRequest = <span class="p_word">None</span>
        branch = Branch()
        
        <span class="p_commentline"># TODO: replace the following with <a href="http://www.rfc-editor.org/rfc/rfc3263.txt">RFC3263</a> to return multiple candidates. Add TCP and UDP and if possible TLS.</span>
        dest = target.dup()
        dest.port = target.port <span class="p_word">or</span> target.secure <span class="p_word">and</span> <span class="p_number">5061</span> <span class="p_word">or</span> <span class="p_number">5060</span>
        <span class="p_word">if</span> <span class="p_word">not</span> isIPv4(dest.host):
            <span class="p_word">try</span>: dest.host = gethostbyname(dest.host)
            <span class="p_word">except</span>: <span class="p_word">pass</span>
        <span class="p_word">if</span> isIPv4(dest.host):
            branch.remoteCandidates = [dest]
        
        <span class="p_commentline"># continue processing as if we received multiple candidates</span>
        <span class="p_word">if</span> <span class="p_word">not</span> branch.remoteCandidates <span class="p_word">or</span> len(branch.remoteCandidates) == <span class="p_number">0</span>:
            self.error(<span class="p_word">None</span>, <span class="p_string">'cannot resolve DNS target'</span>)
            <span class="p_word">return</span>
        target = branch.remoteCandidates.pop(<span class="p_number">0</span>)
        <span class="p_word">if</span> request.method != <span class="p_string">'ACK'</span>:
            <span class="p_commentline"># start a client transaction to send the request</span>
            branch.transaction = Transaction.createClient(self.stack, self, request, self.stack.transport, target.hostPort)
            branch.request = request
            self.branches.append(branch)
        <span class="p_word">else</span>: <span class="p_commentline"># directly send ACK on transport layer</span>
            self.stack.send(request, target.hostPort)

    <span class="p_word">def</span> retryNextCandidate(self, branch):
        <span class="p_triple">'''Retry next DNS resolved address.'''</span>
        <span class="p_word">if</span> <span class="p_word">not</span> branch.remoteCandidates <span class="p_word">or</span> len(branch.remoteCandidates) == <span class="p_number">0</span>:
            <span class="p_word">raise</span> ValueError, <span class="p_string">'No more DNS resolved address to try'</span>
        target = URI(branch.remoteCandiates.pop(<span class="p_number">0</span>))
        branch.request.first(<span class="p_string">'Via'</span>).branch += <span class="p_string">'A'</span> <span class="p_commentline"># so that we create a different new transaction</span>
        branch.transaction = Transaction.createClient(self.stack, self, branch.request, self.stack.transport, target.hostPort)
    
    <span class="p_word">def</span> getBranch(self, transaction):
        <span class="p_word">for</span> branch <span class="p_word">in</span> self.branches:
            <span class="p_word">if</span> branch.transaction == transaction: <span class="p_word">return</span> branch
        <span class="p_word">return</span> <span class="p_word">None</span>
    
    <span class="p_word">def</span> receivedResponse(self, transaction, response):
        <span class="p_triple">'''Received a new response from the transaction.'''</span>
        branch = self.getBranch(transaction)
        <span class="p_word">if</span> <span class="p_word">not</span> branch:
            <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'Invalid transaction received %r'</span>%(transaction)
            <span class="p_word">return</span>
        <span class="p_word">if</span> response.is1xx <span class="p_word">and</span> branch.cancelRequest:
            cancel = Transaction.createClient(self.stack, self, branch.cancelRequest, transaction.transport, transaction.remote)
            branch.cancelRequest = <span class="p_word">None</span>
        <span class="p_word">else</span>:
            <span class="p_word">if</span> response.isfinal: branch.response = response
            <span class="p_commentline"># TODO: self.stack.receivedResponse(self, response)</span>
            self.sendResponseIfPossible()
            
    <span class="p_word">def</span> sendResponseIfPossible(self):
        branches = filter(<span class="p_word">lambda</span> x: x.response <span class="p_word">and</span> x.response.isfinal, self.branches)
        branches2xx = filter(<span class="p_word">lambda</span> x: x.response.is2xx, branches)
        <span class="p_word">if</span> _debug: <span class="p_word">print</span> <span class="p_string">'received %d responses out of %d'</span>%(len(branches), len(self.branches))
        response = <span class="p_word">None</span>
        <span class="p_word">if</span> branches2xx: response = branches[<span class="p_number">0</span>].response
        <span class="p_word">elif</span> len(branches) == len(self.branches): response = branches[<span class="p_number">0</span>].response <span class="p_commentline"># TODO select best instead of first </span>
        <span class="p_word">if</span> response:
            self.branches[:] = [] <span class="p_commentline"># clear the list so that no more responses are accepted.</span>
            response.delete(<span class="p_string">'Via'</span>, position=<span class="p_number">0</span>) <span class="p_commentline"># remove topmost Via header</span>
            self.sendResponse(response)
            
    <span class="p_word">def</span> sendCancel(self):
        <span class="p_triple">'''Cancel a request.'''</span>
        <span class="p_word">for</span> branch <span class="p_word">in</span> self.branches:
            branch.cancelRequest = branch.transaction.createCancel()
            <span class="p_word">if</span> branch.transaction.state != <span class="p_string">'trying'</span> <span class="p_word">and</span> branch.transaction.state != <span class="p_string">'calling'</span>:
                <span class="p_word">if</span> branch.transaction.state == <span class="p_string">'proceeding'</span>:
                    transaction = Transaction.createClient(self.stack, self, branch.cancelRequest, branch.transaction.transport, branch.transaction.remote) 
                branch.cancelRequest = <span class="p_word">None</span>
            <span class="p_commentline"># else don't send until 1xx is received </span>

    <span class="p_word">def</span> timeout(self, transaction):
        <span class="p_triple">'''A client transaction was timedout.'''</span>
        branch = self.getBranch(transaction)
        <span class="p_word">if</span> <span class="p_word">not</span> branch:  <span class="p_word">return</span> <span class="p_commentline"># invalid transaction</span>
        branch.transaction = <span class="p_word">None</span> 
        <span class="p_word">if</span> branch.remoteCandidates <span class="p_word">and</span> len(branch.remoteCandidates)&gt;<span class="p_number">0</span>:
            self.retryNextCandidate(branch)
        <span class="p_word">else</span>:
            self.receivedResponse(<span class="p_word">None</span>, Message.createResponse(<span class="p_number">408</span>, <span class="p_string">'Request timeout'</span>, <span class="p_word">None</span>, <span class="p_word">None</span>, branch.request))
    
    <span class="p_word">def</span> error(self, transaction, error):
        <span class="p_triple">'''A transaction gave transport error.'''</span>
        branch = self.getBranch(transaction)
        <span class="p_word">if</span> <span class="p_word">not</span> branch:  <span class="p_word">return</span> <span class="p_commentline"># invalid transaction</span>
        self.transaction = <span class="p_word">None</span>
        branch.transaction = <span class="p_word">None</span> 
        <span class="p_word">if</span> branch.remoteCandidates <span class="p_word">and</span> len(branch.remoteCandidates)&gt;<span class="p_number">0</span>:
            self.retryNextCandidate(branch)
        <span class="p_word">else</span>:
            self.receivedResponse(<span class="p_word">None</span>, Message.createResponse(<span class="p_number">503</span>, <span class="p_string">'Service unavailable - '</span> + error, <span class="p_word">None</span>, <span class="p_word">None</span>, branch.request))


<span class="p_commentline">#--------------------------- Testing --------------------------------------</span>
<span class="p_word">if</span> __name__ == <span class="p_string">'__main__'</span>:
    <span class="p_word">import</span> doctest
    doctest.testmod()


  </PRE></BODY>
</HTML>
